@Autowired依赖注入HttpServletRequest
场景
通常来说依赖注入的对象一旦创建完成后就不会在改变,因为Spring的默认行为创建的都是单例对象。HttpServletRequest
和HttpServletResponse
不是单例对象,它们都是根据HTTP请求进行创建的,一个HTTP请求对象一个request和response。但是通过@Autowired
可以实现每当一个请求进来时使用的都是当前的request或response对象,
演示代码如下
@RestController
@RequestMapping("/test")
public void TestController {
@Autowired
private HttpServletRequest request;
@GetMapping("/request")
public String test() {
String queryString = request.getQueryString();
}
}
实现原理
实际上,通过@Autowire
注入的HttpServletRequest
只是一个代理对象,其内部会实时获取当前请求对应的真正的HttpServletRequest
对象。
在上面的TestController
中,框架在进行依赖注入HttpServletRequest
时,会去IOC容器中查找类型为HttpServletRequest
的Bean,
首先会调用DefaultListableBeanFactory#doResolveDependency(DependencyDescriptor, String, Set<String>, TypeConverter)
进行依赖的解析,最终会调用到DefaultListableBeanFactory#findAutowireCandidates(String, Class<?>, DependencyDescriptor)
, 该方法主要是从依赖注入源中查找对应类型的Bean,源码如下:
// 存放用于依赖注入的Bean
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
if (autowiringType.isAssignableFrom(requiredType)) {
// 从依赖注入源查找对应类型的Bean
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
// 如果有必要的话,为autowiringValue创建代理对象
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// 省略其他代码...
return result;
}
值得注意的是resolvableDependencies中存放的Bean只用于依赖注入,不用于依赖查找
在this.resolvableDependencies.get(autowiringType);
这段代码中会获取到一个类型为RequestObjectFactory
的Bean,该Bean实现了ObjectFactory
接口,属于WebApplicationContextUtils
的内部类,源码如下
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
@Override
public ServletRequest getObject() {
return currentRequestAttributes().getRequest();
}
@Override
public String toString() {
return "Current HttpServletRequest";
}
}
private static ServletRequestAttributes currentRequestAttributes() {
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
if (!(requestAttr instanceof ServletRequestAttributes)) {
throw new IllegalStateException("Current request is not a servlet request");
}
return (ServletRequestAttributes) requestAttr;
}
通过代码可以看出来RequestObjectFactory
的作用就是实时从ThreadLocal
中获取当前请求对应的request对象,RequestContextHolder
内部使用的就是ThreadLocal
在获取到RequestObjectFactory
对象后,AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType)
这段代码中会为其创建一个代理对象,源码如下
// AutowireUtils#resolveAutowiringValue
public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
// 此时 factory = RequestObjectFactory
ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
// 创建代理对象, requiredType = HttpServletRequest.class
// 并将RequestObjectFactory传入ObjectFactoryDelegatingInvocationHandler中
autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
}
else {
return factory.getObject();
}
}
return autowiringValue;
}
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();
}
// 在代理类中,每次调用HttpServetRequest中的方法都会去RequestObjectFactory中获取线程本 // 地变量中的HttpServletRequest对象,并通过反射调用其对应的方法
try {
return method.invoke(this.objectFactory.getObject(), args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
从源码中可以看出在示例代码TestController
中调用request.getQueryString()
,会直接进入到ObjectFactoryDelegatingInvocationHandler
的invoke()
方法中,然后通过反射的方式调用真正的HttpServletRequest
对象中的方法
RequestObjectFactory 和 RequestAttributes 初始化时机
RequestObjectFactory
在容器启动阶段,会有一个BeanFactory后置处理阶段,其中会调用AbstractApplicatioContext#postProcessBeanFactory(ConfigurableListableBeanFactory)
方法,其中一个子类,AnnotationConfigReactiveWebServerApplicationContext
对其进行了实现,其中会调用到WebApplicationContextUtils#registerWebApplicationScopes(ConfigurableListableBeanFactory, ServletContext)
方法,源码如下
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
@Nullable ServletContext sc) {
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
if (sc != null) {
ServletContextScope appScope = new ServletContextScope(sc);
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
sc.setAttribute(ServletContextScope.class.getName(), appScope);
}
// 添加依赖注入Bean的来源
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
}
// DefaultListableBeanFactory#registerResolvableDependency
public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {
Assert.notNull(dependencyType, "Dependency type must not be null");
if (autowiredValue != null) {
if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
throw new IllegalArgumentException("Value [" + autowiredValue +
"] does not implement specified dependency type [" + dependencyType.getName() + "]");
}
// 添加进依赖注入源
this.resolvableDependencies.put(dependencyType, autowiredValue);
}
}
在上面代码中会将RequestObjectFactory
和其他实现了ObjectFactory
接口的对象添加到依赖注入源中,到这一步也就和上面获取requset对象的过程对应起来了
RequestAttributes
RequestAttributes
在Spring中的多处代码中都有使用到,这里列举两个Web场景下常用的两处
RequestContextFilter中
第一个在过滤器RequestContextFilter
中,会把当前的HttpServletRequest
和HttpServletResponse
都放入ThreadLocal
中,过滤器代码如下
public class RequestContextFilter extends OncePerRequestFilter {
// 省略类中其他代码...
// 该方法属于OncePerRequestFilter的模板方法,
// 会在OncePerRequestFilter#doFilter(ServletRequest, ServletResponse, FilterChain)中被调用
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 创建RequestAttributes的子类对象`ServletRequestAttributes`
ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);
// 初始化RequestContextHolder
initContextHolders(request, attributes);
try {
filterChain.doFilter(request, response);
}
finally {
resetContextHolders();
if (logger.isDebugEnabled()) {
logger.debug("Cleared thread-bound request context: " + request);
}
attributes.requestCompleted();
}
}
private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) {
LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable);
// 将RequestAttributes 放入ThreadLocal中
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
}
}
RequestContextListener中
RequestContextListener
实现了Servlet中的监听器ServletRequestListener
, 当事件发生,会将requset对象放入ThreadLocal
中
public class RequestContextListener implements ServletRequestListener {
private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";
@Override
public void requestInitialized(ServletRequestEvent requestEvent) {
if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
throw new IllegalArgumentException(
"Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
}
HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
ServletRequestAttributes attributes = new ServletRequestAttributes(request);
request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
LocaleContextHolder.setLocale(request.getLocale());
RequestContextHolder.setRequestAttributes(attributes);
}
}