众所周知,在spring的bean中使用HttpServletRequest可以使用 或者在controller的方法入参中加入HttpServletRequest 但是为什么可以这样使用?controller类默认是单例的,使用@Autowired注入的response和request却可以在多个线程中使用,这就出现了作用域request级别的bean注入到singleton级别的bean中去的现象。 那么spring是如何保证在singleton作用域中使用更长作用域的bean的呢? 在此文中说明了spring中,如果需要将作用域较大的bean A注入较小的bean B中时,其实注入的是A的代理对象,在需要时使用代理getObject()来获取一些指定的依赖。 在controller中使用HttpServletRequest时,我们并不需要注入就可以使用。这是因为spring初始化的过程中,就已经把HttpServletRequest注册到容器中去了。通过spring的refresh()方法的 分别在方法入参和controller中引用 通过 看到这里答案已经很明了了,这个
spring如何注入作用域不同的bean源码分析(以HttpServletRequest为例)
1.现象
@Autowired protected HttpServletRequest request;
public void exportOrder(HttpServletRequest request) { return null; }
2.spring如何注入作用域不同的bean
3.HttpServletRequest如何初始化
postProcessBeanFactory(beanFactory)
,
该方法实现的ServletWebServerApplicationContext
的postProcessBeanFactory
调用了WebApplicationContextUtils.registerWebApplicationScopes()
### 4.HttpServletRequest的使用
那么知道了是如何注入之后,那么又是如何使用的呢。使用一个例子来看一看:/** * @author LWong * @date 2020/04/23 */ @RestController("req") public class ExportController { @Autowired private HttpServletRequest httpServletRequest; @PostMapping("export") public void export(HttpServletRequest httpServletRequest1){ String method = httpServletRequest.getMethod(); System.out.println(method); } }
HttpServletRequest
,打断点查看httpServletRequest
和httpServletRequest1
在图片中可以发现httpServletRequest
是一个代理对象是,作为成员变量注入的时候注入的是代理对象,AutowireUtils.ObjectFactoryDelegatingInvocationHandler
的实例,而作为方法参数注入的就是我们一般使用的Request对象。那么来看看这个handler/** * Reflective {@link InvocationHandler} for lazy access to the current target object. */ @SuppressWarnings("serial") private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable { private final ObjectFactory<?> objectFactory; public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) { this.objectFactory = objectFactory; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.equals("equals")) { // Only consider equal when proxies are identical. return (proxy == args[0]); } else if (methodName.equals("hashCode")) { // Use hashCode of proxy. return System.identityHashCode(proxy); } else if (methodName.equals("toString")) { return this.objectFactory.toString(); } try { return method.invoke(this.objectFactory.getObject(), args); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }
this.objectFactory.getObject()
方法进入到WebApplicationContextUtils.currentRequestAttributes()
从这个又要进入RequestContextHolder的getRequestAttributes
方法
而requestAttributesHolder正是初始化的threadLocal,保证了线程安全
RequestContextHolder
的ThreadLocal成员变量就是实现的关键所在,它存放了每个线程对应的Request对象,因此在@Controller中调用作为成员变量注入的代理类的方法时,最终可以取到当前线程相对应的Request对象,并调用Request对应的方法,这样@Controller中的成员变量不需要重复注入(它一直都是最初bean初始化时注入的代理类),也避免了线程不安全的问题。
5.总结
HttpServletRequest
时,实际注入的是spring框架生成的代理对象,是ObjectFactoryDelegatingInvocationHandler
的实例。在我们调用这个成员变量的方法时,最终是调用了objectFactory
的getObject()
对象的对应方法,在这里objectFactory
是RequestObjectFactory
这个类的对象。RequestObjectFactory
的getObject
方法是从RequestContextHolder
的threadlocal中去取值的。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算