request request.setattributee 线程安全吗

【资深的你,进来指点下】SpringMvc Controller的线程安全! - 开源中国社区
当前访客身份:游客 [
当前位置:
SpringMvc Controller的**线程安全**!
为什么下面的代码是线程安全的?
@Controller
public class UserController{
@Autowired
private HttpSession session
@RequestMapping(xxxxxxx)
public void getUser{
session.get ...
session.set...
大家都知道spring bean默认是单例的。但是这个地方的session对象
为什么没有线程安全问题?(经过测试)
如果是其他自定义Object 有全局属性 应该有线程安全问题(猜想)
求,牛人解答。谢谢
共有5个答案
<span class="a_vote_num" id="a_vote_num_
和 @小乞丐 各说对了一半。
在项目启动和运行时,Controller实例中的HttpSession session并不是HttpSession 实例,而是一个代理,是org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler代理了HttpSession ,可通过这个代码求证:System.out.println(Proxy.getInvocationHandler(session));
只有当你真正调用HttpSession 里面非java.lang.Object方法时才会真真去调用被代理的HttpSession里面的方法。
-----------------------------
说一下session.get ...过程:首先从对象工厂从Threadlocal中取得HttpSession实例,然后通过反射调用该实例的set方法。
把下面这个方法加到你的Controller中然后运行你的项目,你就知道了
@PostConstruct
public void init() {
System.out.println(session.toString());
session.setAttribute("ddfaf", "dddddddddddddd");
Current HttpSession
[WARN] ][09:54:49,333]
[ org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:487) ] Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'colorController': Invocation o nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:549)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1282)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:518)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:499)
at ponent.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:224)
at ponent.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at runjettyrun.Bootstrap.main(Bootstrap.java:97)
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:275)
at org.springframework.web.context.support.WebApplicationContextUtils.access$400(WebApplicationContextUtils.java:64)
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:332)
at org.springframework.web.context.support.WebApplicationContextUtils$SessionObjectFactory.getObject(WebApplicationContextUtils.java:327)
at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:307)
at $Proxy10.setAttribute(Unknown Source)
at mon.controller.ColorController.init(ColorController.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:349)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:300)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
... 24 more
--- 共有 1 条评论 ---
谢谢你的总结,和论证。
(1年前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
请参考:http://lavasoft./9
--- 共有 1 条评论 ---
你没明白我意思?难道单例中存在全局变量会有线程安全问题 我不知道?我问的为什么单例的Controller中 存在全局变脸HttpSession的对象,但实际上多个用户访问的时候是线程安全的。明白么~~我想知道Spring怎么实现的
(1年前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
这里的session对象是线程安全的;spring 在初始化的时候 会对所有的让其注入的filed 都会找到对应的对象进行set注入。session set方法注入,说白了就是赋值,然后就session 对象(这里已经实例化) 放在map中。
当请求到达产生时,会再filter中根据请求url得到你要请求的action 和method,然后在map中拿到你这个action对象和它的method,然后method.invoke()调用,当你在method中使用的session 实际上在初始化这个action类的时候,就对其filed 已经实例化了。
所以无论多少请求多少线程,得到的session 对象 永远都是单利的。所以说是线程安全的。
不知道你说的是不是这个?&
--- 共有 4 条评论 ---
: 恩,实例化应该是初始化完成的事情,然后第一次请求应该返回这个对象的代理,我以前写过类似的框架玩,我采用的方式在第一请求将代理对象放在Map中,第二请求直接获取这个代理对象。spring 源码没看, 不知道是每次请求都去添加一次代理吗?
(1年前)&nbsp&
: 确实实例化了,但给的HttpSession的一个代理。
当请求到达时,实际使用的是ThreadLocal中保存的session。
(1年前)&nbsp&
: 在这里并不是,这里的session 是class 的一个 filed,在初始化bean.xml的时候,就会将class中的filed 实例化赋值。
(1年前)&nbsp&
"然后就session 对象(这里已经实例化) 放在map中。
当请求到达产生时,"
我认为现有请求再有session。
(1年前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
无状态对象
由于 Spring 的事务管理器是通过线程相关的 ThreadLocal 来保存数据访问基础设施,再结合 IOC 和 AOP 实现高级声明式事务的功能,所以 Spring 的事务天然地和线程有着千丝万缕的联系。
我们知道 Web 容器本身就是多线程的,Web 容器为一个 Http 请求创建一个独立的线程,所以由此请求所牵涉到的 Spring 容器中的 Bean 也是运行于多线程的环境下。在绝大多数情况下,Spring 的 Bean 都是单实例的(singleton),单实例 Bean 的最大的好处是线程无关性,不存在多线程并发访问的问题,也即是线程安全的。
一个类能够以单实例的方式运行的前提是“无状态”:即一个类不能拥有状态化的成员变量。我们知道,在传统的编程中,DAO 必须执有一个 Connection,而 Connection 即是状态化的对象。所以传统的 DAO 不能做成单实例的,每次要用时都必须 new 一个新的实例。传统的 Service 由于将有状态的 DAO 作为成员变量,所以传统的 Service 本身也是有状态的。
但是在 Spring 中,DAO 和 Service 都以单实例的方式存在。Spring 是通过 ThreadLocal 将有状态的变量(如 Connection 等)本地线程化,达到另一个层面上的“线程无关”,从而实现线程安全。Spring 不遗余力地将状态化的对象无状态化,就是要达到单实例化 Bean 的目的。
由于 Spring 已经通过 ThreadLocal 的设施将 Bean 无状态化,所以 Spring 中单实例 Bean 对线程安全问题拥有了一种天生的免疫能力。不但单实例的 Service 可以成功运行于多线程环境中,Service 本身还可以自由地启动独立线程以执行其它的 Service。下面,通过一个实例对此进行描述:
--- 共有 1 条评论 ---
谢谢你的回答,使我茅塞顿开。下一步应该是去看看Spring怎么利用ThreadLocal把一个有状态的类变成无状态的类。嘿嘿
(1年前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
引用来自“小乞丐”的评论
这里的session对象是线程安全的;spring 在初始化的时候 会对所有的让其注入的filed 都会找到对应的对象进行set注入。session set方法注入,说白了就是赋值,然后就session 对象(这里已经实例化) 放在map中。
当请求到达产生时,会再filter中根据请求url得到你要请求的action 和method,然后在map中拿到你这个action对象和它的method,然后method.invoke()调用,当你在method中使用的session 实际上在初始化这个action类的时候,就对其filed 已经实例化了。
所以无论多少请求多少线程,得到的session 对象 永远都是单利的。所以说是线程安全的。
不知道你说的是不是这个?&
感谢两位的回答,嘿嘿,首先Spring“注入”的所有类都是代理类,否则Spring没法帮你完成很多注解的功能。
其二,其实开始的时候我已经猜想到是通过TheadLocal来完成的,只是当时被Tomcat的源码误解了,因为我当时想Tomcat服务器用的是NIO(nonBlocking IO) 所以每个请求进来都不一定是同一个线程,但是我没有想到Spring 应该是在请求进来的时候ThreadLocal.set(Session),然后在请求的生命周期中都是一个Thread ,执行完后ThreadLocal.remove(Session)的,诶,按道理这么简单不应该想不到了,想想也是对ThreadLocal不熟悉,不过通过你们的回答 感觉更透彻了。3Q
更多开发者职位上
有什么技术问题吗?
Ambitor...的其它问题
类似的话题getAttribute
setAttribute
request.setAttribute()、session.setAttribute()和request.getParameter()的联系与区别&&
16:51:00|&&分类:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:37329次
排名:千里之外
原创:35篇
转载:93篇
(5)(12)(50)(6)(20)(24)(4)(8)session 和request 区别_百度知道request.setAttribute()如何就取不到值 - Java Web开发当前位置:& &&&request.setAttribute()如何就取不到值request.setAttribute()如何就取不到值&&网友分享于:&&浏览:371次request.setAttribute()怎么就取不到值我在ACTION 中request.setAttribute(“name”,List);JSP页面中request.GetAttribute(&name&);为什么页面中就取不到值呢?在ACTION 中值是实在存在的~我的JSP页面是window.open(&&%=request.getContextPath()%&/action/addCondition.jsp&);我还用了另外一中方法第一个JSP页面提交到ACTION中的时候,open一个新窗口。并在ACTION中把数据封装到了一个vo中。在OPEN的JSP中能取到值但是总是晚一步。比如说第一JSP传的是1,VO中封装了1。JSP传递的是2,vo中封装的是2。但实际效果是第一次请求传递1后第2个JSP页面为NULL。第2次请求传递2或者其他更多其他参数的时候,第2个JSP页面显示的却是1。就是第2个JSP页面会显示上一次应该得到的值~非常郁闷~------解决方案--------------------
探讨window.open(& &%=request.getContextPath()%&/action/addCondition.jsp&); 取不到值是你这样转向的问题,你如果换成session存,这样就可以取到,用request存,在服务器端转各可以取到, window.open()是基于浏览器的,取不到值是对的,
------解决方案--------------------
jsp1提交参数到ACTION和OPEN一个新窗口JSP2其实你在submit的时候肯定就open了 这个时候你确定你的action已经在后台处理完数据对数据进行封装了吗
你forward到新页面还是能够取到的在不然根据你的需求用session也是不行的 除非你把提交给action的参数传给jsp2里面& 例如:onsubmit=function(){window.open(jsp2.jsp?parame1=***&....)}jsp2.jsp中使用&c:import url=&***.action/do?parame1=***&&&&/c:import&后面加处理代码MovementCondition ac = new MovementCondition();List li = (List) ac.getConditionC()确保数据处理过后进行调用处理
------解决方案--------------------探讨jsp1提交参数到ACTION和OPEN一个新窗口JSP2 其实你在submit的时候肯定就open了 这个时候你确定你的action已经在后台处理完数据对数据进行封装了吗
你forward到新页面还是能够取到的 在不然根据你的需求用session也是不行的 除非你把提交给action的参数传给jsp2里面 例如: onsubmit=function() { window.open(jsp2.jsp?parame1=***&....) } jsp2.jsp中使用 &c:import url=&***.action/do?parame1=***&&& …
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&}

我要回帖

更多关于 java 线程安全的set 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信