Servlet中的这些有关问题,你注意到了吗
最开始的时候,我并没有系统地学过Servlet,因为第一次看的时候觉得它好简单,然后就直接学了Struts 2。但问题也就因为我没有系统地学过Servlet而产生了,在Struts 2中很多东西都被封装好了,但实现的机制还是用的Servlet,而我就有些东西无法理解了,于是决定回过头来好好学了下Servlet。
说实话,目前市面上好多讲Servlet的书都讲得相当浅,一般都是随便讲一下应用就带过了,然后就是搞几个所谓的实际项目来凑下字数。很幸运,我找到一本很不错的书,孙鑫老师写的《Servlet/JSP深入详解》,个人感觉讲得非常不错,看完之后,收获还是蛮大的。于是,决定把一些一般的书中很少讲到但很重要的细节拉出来总结一下。
第一点被我拉出来的就是Servlet的线程安全问题了,明确说明一下:Servlet不是线程安全的。在Servlet规范定义中,在默认情况下(Servlet不是在分布式的环境中部署),Servlet容器对声明的每一个Servlet只创建一个实例。如果有多个客户请求同时访问这个Servlet,Servlet采用多线程的方式来处理这些请求,Servlet容器维护了一个线程池来服务请求。线程池实际上是等待执行代码的一组线程,这些线程叫做工作者线程(WorkerThread),Servlet窗口使用一个调度者线程(Dispatcher Thread)来管理工作者线程。当容器收到一个访问Servlet的请求时,调度者线程从线程池中选取一个工作者线程,将请求传递给该线程,然后由这个线程执行Serlvet的service()方法。
Servlet的线程安全问题也就因此产生,假设一个Servlet中有一个实例变量name,当两个用户同时访问一个Servlet时,Servlet中name这个实例变量还是安全的吗?答案是否定的。问题出在name是个实例变量,原因我想大家都明白了。解决的办法有两个:一个就是把name这个实例变量定义为本地变量,这个每一个线程就都将拥有这个变量的拷贝,线程对自己栈中的本地变量的改变不会影响到其他线程的本地变量的拷贝,因此,在请求处理过程中,变量name的值也就不会被别的线程所改变。在Servlet的开发中,本地变量总是线程安全的。第二种解决办法就是把方法(如doGet(),doPost()等)进行同步处理,这样肯定也是可以解决问题的,但产生的负使用就是访问同一个Servlet的请求将排队,一个线程处理完请求后,才能执行另一个线程,带来的性能问题也就不好怎么说了。
同样的思考方法,可以得到下面的结论:ServletContext属性的访问也不是线程安全的,HttpSession由于其本身的特性(只能在处理属于同一个Session的请求的线程中被访问)决定了它是线程安全的,ServletRequest对象只在一个线程中被访问,故而也是线程安全的。
第二点就是Servlet的异常处理机制,较少看到有书专门讲这个的,有兴趣的朋友可以找点资料看一下下,我没怎么弄懂,也不太清楚有哪些地方要使用。
第三点是Servlet的会话跟踪技术,在Servlet规范中,有三种机制用于会话跟踪:1.SSL(安全套接字层)会话;2.Cookies;3.URL重写。
SSL是一种运行在TCP/IP之上的像HTTP这种应用协议之下的加密技术,SSL可以让采用SSL的服务器认证采用SSL的客户端,并且在客户端和服务器之间保持一种加密的连接。Cookies是在响应报头和请求报头中被传送的,不与传送的内容混淆在一起,所以Cookies的使用对于用户来说是透明的,如果用户禁用Cookies,那么Web服务器就无法利用Cookies来跟踪用户的会话了,而要采用URL重写机制。URL重写就是在URL中附加标识用户的SessionID,Servlet容器解释URL时取出SessionID,根据SessionID将请求与特定的Session关联。
第四点是Cooikes与Session的对比,两者的最大区别在于:Session在服务器端保存信息,Cookies在客户端保存信息。为了跟踪用户的会话,服务器端在创建Session后,需要将SessionID交给客户端,在客户端下次请求时,将这个ID随请求一起发送回来,可以采用Cookies或URL重写的方式,将SessionID发送给客户端。另外,保存SessionID的Cookies在关闭浏览器后就删除了,不能在多个浏览器进程间共享。如果需要对Session进行持久化,则需要将内存中Session对象保存到持久存储设备中,可通过对象序列化的技术来实现,当需要重新加载Session对象时,通过对象反序列化的技术在内存中重新构造Session对象。这就要求HttpSession的实现类要实现Serializable接口,同时Session中保存的对象所属的类也要实现该接口。
学到目前,虽然自己没有学出个什么名堂,但我终于明白了所谓的MVC框架的意义,像Struts、Struts 2、SpringMVC其实并不难,而且谁也无法保证它们会火多久,自己以后会不会用到它们,但无论怎样,基础是永远都不会变的。所以,不论这些东西学得怎么样,Servlet跟JSP这些基础一定要学好,有了这些基础,感觉学这些框架还是蛮好上手的,至少我个人现在是这种想法。
按理说创建Session对象之后返回给浏览器一个sessionid,下次访问带着这个sessionid就能对应到相应的session,但是想想平常开发,从来没有写过
http://url&jsessionid=12345,但确实能访问到session信息,难道浏览器自己附加sessionid给服务器?
是啊,开始我也是觉得servlet简单,没怎么弄懂就去学STRUT2了,后来发现一些东西根本理解不了。后来又重新开始重视servlet,开始看孙小姐那本很厚的书。现在很多问题搞清了,知道struts其实就是对servlet的封装,ACTION其实就是替代了servlet工作,知道一个struts2请求在后台工作原理,以前连javaweb和servlet的生命周期及加载顺序都没搞清,现在想想真是可笑!
孙小姐?你不是说孙鑫吧。。。如果你不是开玩笑的话我告诉你,他是男的。。。
有一个事情一直没搞懂:在服务器上创建Session保存信息,但是服务器怎么判断哪个Session对象属于哪个用户?
按理说创建Session对象之后返回给浏览器一个sessionid,下次访问带着这个sessionid就能对应到相应的session,但是想想平常开发,从来没有写过
http://url&jsessionid=12345,但确实能访问到session信息,难道浏览器自己附加sessionid给服务器?
个人觉得第一个问题,应该Session中还封装了客户端的mac地址等可以识别客户端的信息。
第二个问题也是一样,sessionid已经被封装在了Session中了, 不需要自己去实现
第二个问题也是一样,sessionid已经被封装在了Session中了, 不需要自己去实现
unsid 写道
有一个事情一直没搞懂:在服务器上创建Session保存信息,但是服务器怎么判断哪个Session对象属于哪个用户?按理说创建Session对象之后返回给浏览器一个sessionid,下次访问带着这个sessionid就能对应到相应的session,但是想想平常开发,从来没有写过http://url&jsessionid=12345,但确实能访问到session信息,难道浏览器自己附加sessionid给服务器?个人觉得第一个问题,应该Session中还封装了客户端的mac地址等可以识别客户端的信息。第二个问题也是一样,sessionid已经被封装在了Session中了, 不需要自己去实现
我的问题是,无论session用什么识别,我从来没有在请求url中添加过任何东西就能识别,除非是浏览器自己在发送过程中添加的
个人觉得第一个问题,应该Session中还封装了客户端的mac地址等可以识别客户端的信息。
第二个问题也是一样,sessionid已经被封装在了Session中了, 不需要自己去实现renny 写道
unsid 写道
有一个事情一直没搞懂:在服务器上创建Session保存信息,但是服务器怎么判断哪个Session对象属于哪个用户?按理说创建Session对象之后返回给浏览器一个sessionid,下次访问带着这个sessionid就能对应到相应的session,但是想想平常开发,从来没有写过http://url&jsessionid=12345,但确实能访问到session信息,难道浏览器自己附加sessionid给服务器?个人觉得第一个问题,应该Session中还封装了客户端的mac地址等可以识别客户端的信息。第二个问题也是一样,sessionid已经被封装在了Session中了, 不需要自己去实现
我的问题是,无论session用什么识别,我从来没有在请求url中添加过任何东西就能识别,除非是浏览器自己在发送过程中添加的
本来就是啊,既然那些东西都已经自动封装在Session中了,当然也就不需要在请求URL中就可以识别了的,否则就不叫自动封装,叫手工添加了吧
我的问题是,无论session用什么识别,我从来没有在请求url中添加过任何东西就能识别,除非是浏览器自己在发送过程中添加的
本来就是啊,既然那些东西都已经自动封装在Session中了,当然也就不需要在请求URL中就可以识别了的,否则就不叫自动封装,叫手工添加了吧
unsid 写道
个人觉得第一个问题,应该Session中还封装了客户端的mac地址等可以识别客户端的信息。第二个问题也是一样,sessionid已经被封装在了Session中了, 不需要自己去实现renny 写道unsid 写道有一个事情一直没搞懂:在服务器上创建Session保存信息,但是服务器怎么判断哪个Session对象属于哪个用户?按理说创建Session对象之后返回给浏览器一个sessionid,下次访问带着这个sessionid就能对应到相应的session,但是想想平常开发,从来没有写过http://url&jsessionid=12345,但确实能访问到session信息,难道浏览器自己附加sessionid给服务器?个人觉得第一个问题,应该Session中还封装了客户端的mac地址等可以识别客户端的信息。第二个问题也是一样,sessionid已经被封装在了Session中了, 不需要自己去实现我的问题是,无论session用什么识别,我从来没有在请求url中添加过任何东西就能识别,除非是浏览器自己在发送过程中添加的本来就是啊,既然那些东西都已经自动封装在Session中了,当然也就不需要在请求URL中就可以识别了的,否则就不叫自动封装,叫手工添加了吧
可是关键是,你所说的自动封装,是服务器的实现,服务器怎么封装都行,自己的东西随便装
可是提交什么东西是浏览器的实现,如果服务器定义某些标示,它怎可能强制要求浏览器去实现,如果浏览器没有实现的话,有需要我们手动url重写,唯一可能江通的方法就是session借用了http协议规范的传输客户的头信息作为客户标识.
可是关键是,你所说的自动封装,是服务器的实现,服务器怎么封装都行,自己的东西随便装
可是提交什么东西是浏览器的实现,如果服务器定义某些标示,它怎可能强制要求浏览器去实现,如果浏览器没有实现的话,有需要我们手动url重写,唯一可能江通的方法就是session借用了http协议规范的传输客户的头信息作为客户标识.
服务器端通过Cookies或URL重写把sessionid发送给客户端,这样客户端就有了这个sessionid,客户端发送信息的时候不一定要通过URL才能发送sessionid啊,可以有post方式或者借助http协议来发送吧
LZ:
同样的思考方法,可以得到下面的结论:ServletContext属性的访问也不是线程安全的,HttpSession由于其本身的特性(只能在处理属于同一个Session的请求的线程中被访问)决定了它是线程安全的,ServletRequest对象只在一个线程中被访问,故而也是线程安全的。
对于HttSession的结论不要下的太快哦!!
小生也记得孙老师在“Session和Cookie的深入研究”中介绍过,用户可以打开多个同时属于一个进程的浏览器窗口,在这些窗口中的访问请求,属于同一个Session呀。。。
所以Session对象的属性访问不是线程安全的.
呵呵~
LZ:
同样的思考方法,可以得到下面的结论:ServletContext属性的访问也不是线程安全的,HttpSession由于其本身的特性(只能在处理属于同一个Session的请求的线程中被访问)决定了它是线程安全的,ServletRequest对象只在一个线程中被访问,故而也是线程安全的。
对于HttSession的结论不要下的太快哦!!
小生也记得孙老师在“Session和Cookie的深入研究”中介绍过,用户可以打开多个同时属于一个进程的浏览器窗口,在这些窗口中的访问请求,属于同一个Session呀。。。
所以Session对象的属性访问不是线程安全的.
嗯,那是那是,我确实说错了,不好意思,非常谢谢你的纠正
可是关键是,你所说的自动封装,是服务器的实现,服务器怎么封装都行,自己的东西随便装
可是提交什么东西是浏览器的实现,如果服务器定义某些标示,它怎可能强制要求浏览器去实现,如果浏览器没有实现的话,有需要我们手动url重写,唯一可能江通的方法就是session借用了http协议规范的传输客户的头信息作为客户标识.
服务器端通过Cookies或URL重写把sessionid发送给客户端,这样客户端就有了这个sessionid,客户端发送信息的时候不一定要通过URL才能发送sessionid啊,可以有post方式或者借助http协议来发送吧
unsid 写道
可是关键是,你所说的自动封装,是服务器的实现,服务器怎么封装都行,自己的东西随便装可是提交什么东西是浏览器的实现,如果服务器定义某些标示,它怎可能强制要求浏览器去实现,如果浏览器没有实现的话,有需要我们手动url重写,唯一可能江通的方法就是session借用了http协议规范的传输客户的头信息作为客户标识.服务器端通过Cookies或URL重写把sessionid发送给客户端,这样客户端就有了这个sessionid,客户端发送信息的时候不一定要通过URL才能发送sessionid啊,可以有post方式或者借助http协议来发送吧
那问题就归结为: 是否标准的http post请求,会默认将sessionid作为请求的一部分发送给服务器?
平常登陆之后能处处访问是因为服务器保存session,如果关闭浏览器,服务器并不会清除session,因为关闭浏览器时服务器并不知道你关闭了,并不会在关闭之后给服务器发送一个关闭的信息,服务器上的session一旦创建只能靠超时关闭。而至于关闭浏览器还需要从新登陆,是因为关闭时候清空了cookie,而找不到对应的sessionid,进而言之,反复关闭反复登陆会在服务器上创建很多个session,你只持有最近的那个sessionid。
将这个问题引申一下,是不是可以得到如下结论?
平常登陆之后能处处访问是因为服务器保存session,如果关闭浏览器,服务器并不会清除session,因为关闭浏览器时服务器并不知道你关闭了,并不会在关闭之后给服务器发送一个关闭的信息,服务器上的session一旦创建只能靠超时关闭。而至于关闭浏览器还需要从新登陆,是因为关闭时候清空了cookie,而找不到对应的sessionid,进而言之,反复关闭反复登陆会在服务器上创建很多个session,你只持有最近的那个sessionid。
发了篇纯粹讲session与cookies的文章在你的收件箱里,有时间看下,应该会有帮助的
奠好基础改大楼!!
说一下,HTTPSESSION也不是线程安全的,因为如果一个请求的操作比较长,而同一个客户的另一个请求也到达的时候,仍然会出现不正确的Access,从而出现各种灵异事件
下面的评论中我已经声明过这个问题及其原因了,所以就不再说明
按理说创建Session对象之后返回给浏览器一个sessionid,下次访问带着这个sessionid就能对应到相应的session,但是想想平常开发,从来没有写过
http://url&jsessionid=12345,但确实能访问到session信息,难道浏览器自己附加sessionid给服务器?
打印看一下cookies里有什么