勤学教育网合作机构>石家庄培训>

石家庄兄弟连教育

欢迎您!

全国统一学习专线 8:30-21:00
石家庄兄弟连教育

石家庄兄弟连分层次分阶段的学习,由浅入深,根据学员的不同层次因材施教,授课中使用的案例都是真实的案例

石家庄兄弟连教育> 石家庄教育培训>

石家庄java高级培训

  • 课程介绍

  • 相关知识

  • 2019-11-13
石家庄兄弟连java培训

Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。Java语言设计成适应于变化的环境,它是一个动态的语言。例如,Java中的类是根据需要载入的,甚至有些是通过网络获取的。

石家庄兄弟连课程体系




java发展前景  Java发展前景  
Java语言为与数据库联系紧密设计了Java servlet和SQL-J技术,以及JSP技术。随着JSP技术的发展,使JAVA语言的网络应用更为实际化、更高效快捷,成为IT产业常用的技术。JSP以Java语言作为其服务器端的使用语言,结合了JAVA SCRIPT等多种其他客户端语言,使网络浏览器更为方便的展现。在远程网络教学方面,由于JAVA改变了传统的基于Microsoft Front Page或HTML语言制作的Web页面形态,使网络远程教学更加朝着动态、便捷化、安全化的方向发展,丰富了网络远程教学的手段和覆盖面。
 

大咖教学天团,课程体系引领IT革新
他们曾经敲过的代码现如今已是业界标杆,是中国互联网的参与者与见证者!

  • 马如忠 马如忠 icon

    精通Java、C、C++等主流开发语言,5年以上开发经验,非常丰富的IT从业经验和教育心得,兄弟连特色JAVA讲师,曾担任达内课程总监级讲师。

  • 李康 李康 icon

    曾任用友软件,飞企集团等上市公司技术总监,CTO等职务,12年以上的软件开发和项目管理经验,领导并参与研发中国移动ERP终端系统。


石家庄兄弟连除了强大的线下集中培训外,为在职和自学能力较强人士量身打造的IT云课堂,将线上课程与线下新的面授课同步,并通过一对一贴身服务等措施,实现了优质的教学效果。石家庄兄弟连还与国内200多所高等院校展开深度合作,让在校大学生参与真实的企业级项目研发,独立设计开发商业项目,享受到和石家庄兄弟连学员一样的企业级项目实战训练,广受各界好评。


体验才是王道
高起点才更牛叉
缔造Java课程行业新标准
 
 

详情请进入 石家庄兄弟连教育 已关注:9494 咨询电话:

相关知识点:引言:如果你也是开发者的话,你很可能已经知道PoLA法则(Principle of Lease Astonishment)。那么,看看这篇文章讲述的充满奇幻色彩的调试经历,来见识一下PoLA是如何与HttpURLConnection发生了关联。

如果你和我一样也是开发者的话,你很可能已经听说过“PoLA”原则,或者叫作“产生最少意外”原则。意思非常简单,就是不要让你的用户感到惊讶。或者更明确一些,就像本文这种情况,不要让另外一个开发者感到惊讶。不幸的是,我上个星期就遇到了大大超出我意外的事情,我们有个服务的客户调用端总是发出一些垃圾的请求。

你说垃圾请求吗?是的,就像这样,我们完全不清楚这些请求是从哪里来的。又是这样一个时刻,经理们毫无头绪,抱头乱窜,惊呼“我们肯定是被黑客攻击了”,或者 ”有人把防火墙给关掉了。 包br />
无论如何,先说点背景情况吧,我们的项目里有自动记录活动日志的功能,当某些情况下,比如一个进程启动的时候就会进行记录。这包括我们那出问题的网络服务客户端和服务端,因为它们两者都属于系统的一部分。在某些时候,我们注意到,服务端的响应还没有发出的时候,另外一个来自同样客户端的请求又发了过来。这个真是出乎意料的,因为客户端代码是单线程的,也没有其他的客户端掺和进来。审查代码、测试之后,结论是我们的客户端不可能在第一个请求还没结束的时候再同时发出另外一个。

经过一整天的调试和研究日志发现,事实上,在服务端处理还未结束的时候客户端其实已经断开连接了。所以,这些请求终究并不是同时发生的,但是为什么我们花了一整天的时间才发现呢?这跟我们玩了一整天的星球大战有啥区别?

好吧,其实也不是。我们发现了罪魁祸首,服务端的容器软件HTTP的读超时设置被调得太低了。服务端的日志显示的确生成了响应,但是客户端却在此之前已经断开了,因为服务器端发生了读超时。这些在服务器端当然没有日志记录,因为这种行为是更低一层协议决定的(HTTP栈),而不是服务端的应用代码。

是的,没错,我听明白了,但是客户端的日志该怎么解释?客户端是不是应该抛出一个“ReadTimeoutException”异常,或者类似的玩意,然后可以写到日志里?然而,没错,事实上,并没有。就像现在发现的一样,真正的意外来自HttpURLConnection类的内部(更确切地说,是默认的Oracle的官方实现sun.net.www.protocol.http.HttpURLConnection)。

你以前是否知道HttpURLConnection的默认实现有个在某些情形下自动重试的特性?好吧,我之前就不知道。当时的情况是,客户端的确触发了超时异常,但是却被HttpURLConnection给捕捉了,而它自己决定重新尝试一次。这就意味着,你调用了HttpURLConnection的read()方法,它阻塞了,你正在等待,看起来就好像是在等待第一次请求的响应一样。但是在HttpURLConnection内部,它作了不止一次尝试,因此创建了不止一个socket连接。这就解释了为什么第二次及以后的请求永远在日志里找不到,因为这些第二次之后的请求是HttpURLConnection内部发起的。

让我们上一些代码重现一下。

import java.net.HttpURLConnection;

import java.net.InetSocketAddress;

import java.net.SocketTimeoutException;

import java.net.URL;

import java.util.concurrent.Executors;

import com.sun.net.httpserver.HttpServer;

public class TestMe {

public static void main(String[] args) throws Exception {

startHttpd();

HttpURLConnection httpURLConnection=(HttpURLConnection) new URL("http://localhost:8080/").openConnection();

if (!(httpURLConnection instanceof sun.net.www.protocol.http.HttpURLConnection)) {

throw new IllegalStateException("Well it should really be sun.net.www.protocol.http.HttpURLConnection. "

+ "Check if no library registered it's impl using URL.setURLStreamHandlerFactory()");

}

httpURLConnection.setRequestMethod("POST");

httpURLConnection.connect();

System.out.println("Reading from stream...");

httpURLConnection.getInputStream().read();

System.out.println("Done");

}

public static void startHttpd() throws Exception {

InetSocketAddress addr=new InetSocketAddress(8080);

HttpServer server=HttpServer.create(addr, 0);

server.createContext("/", httpExchange -> {

System.out.println("------> Httpd got request. Request method was:" + httpExchange.getRequestMethod() + " Throwing timeout exception");

if (true) {

throw new SocketTimeoutException();

}

});

server.setExecutor(Executors.newCachedThreadPool());

server.start();

System.out.println("Open for business.");

}

}

运行之,将会得到类似下面的输出。

Open for business.

Reading from stream...

------> Httpd got request. Request method was:POST Throwing timeout exception

------> Httpd got request. Request method was:POST Throwing timeout exception

Exception in thread "main" java.net.SocketException: Unexpected end of file from server

at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:792)

...

注意,我们的监听服务被调用了两次,但是我们只发了一个请求。如果我们加上-Dsun.net.http.retryPost=false这个属性再运行一次的话,我们会得到下面的输出:

------> Httpd got request. Request method was:POST Throwing timeout exception

Exception in thread "main" java.net.SocketException: Unexpected end of file from server

at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:792)

...

好,先把这事放一边,我想问的是,到底是谁搞出这么个设计来,既没文档描述又没有可配置选项?为啥我做了十五年的Java开发,却对此一无所知?更要命的是,为什么它要对一个构造异常的POST请求进行重试呢?这是对PoLA赤裸裸的违背!

现在你可能已经猜到了,这是一个BUG(链接:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6382788)。当然了,说是BUG并不是指的它的重试机制,而是指它为什么对异常POST请求也会进行重试。按照HTTP RFC的规范,POST请求并非幂等,因此多次提交POST会带来服务器端数据的改变。但是别担心,Bill早就把这个BUG修改好了。Bill的解决方法是加了一个开关。Bill了解向后兼容原则。Bill认为最好的方法是添加一个默认开启的开关,这样可以保证这个BUG的向后兼容。Bill笑了。Bill已经能够看见全球无数的Java开发者掉进这个大坑时惊愕的面孔。但是,你们都别学Bill好吗?

经过好几天激动人心的调试,最后问题解决的方式却略显轻巧,仅仅指定了一个属性就搞定了。无论如何,这个设计真是着实让我很意外,因此我还专门写了这篇文章来讲述,并且,你也看到了这篇文章。

为了完整起见,再提醒一下,如果你让这段代码在容器环境里执行的话,结果可能会不同。你的容器或者你的代码所依赖的库有可能会替换掉Oracle默认的内部实现,请参考URL.setURLStreamHandlerFactory()。现在你可能会问,那个家伙当时为什么要使用HttpURLConnection呢?他难道是坐着演讲巡游车上班吗(原文Wooden Soapbox,由来参见https://en.wikipedia.org/wiki/Soapbox)?他难道是用剪子来割草吗?建议他传递信息的时候最好还是使用烽火吧!当然了,你这么想我也不能责怪你。我们出问题的代码有点特别,使用的是SAAJ中的SOAPConnectionFactory,而SOAPConnectionFactory内部又默认使用了HttpURLConnection,如果没有其他代码来注册其他的实现类的话,使用的当然就是默认的Oracle实现喽~

  • 校区地址
  • 学校相册
  • 热门课程
  • 同类机构
  • 其他课程

温馨提示:提交留言后老师会第一时间与您联系!热线电话:

手机访问

#tel_400#