SpringMVC源码剖析之自动注入Request,Response

2 篇文章 0 订阅

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、测试用例

二、源码分析

1.request属性注入过程

2.RequestObjectFactory

总结


前言

      我们在使用SpringMvc处理请求的时候,可以在controller层或者service层注入HttpServletRequest对象,controller是一个单例对象,在容器初始化的过程中会对其进行属性注入,然而httprequest是随着每次请求的变化而变化的,所以基本不可能在初始化的时候得到。本篇文章主要探究spring对注入request对象的处理。


一、测试用例

        测试用的案例比较简单,就是在controller中注入了request和response对象,并获取请求url;

@Controller
@RequestMapping("/demo")
public class DemoController  {

	@Autowired
	HttpServletRequest request;
	@Autowired
	HttpServletResponse response;

	@RequestMapping(value = "/testRequest",method = RequestMethod.GET)
	@ResponseBody
	public String testRequest() {
		response.addHeader("header","header");
		return request.getRequestURL().toString();
	}
}

二、源码分析

1.request属性注入过程

        代码通过分析源码得知,在注入request对象的时候,是在resolvableDependencies中找到了RequestObjectFactory类;

	protected Map<String, Object> findAutowireCandidates(
			@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
		
		for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
			// 得到当前Bean的类型
			Class<?> autowiringType = classObjectEntry.getKey();
			if (autowiringType.isAssignableFrom(requiredType)) {
				// 获取缓存中的值
				Object autowiringValue = classObjectEntry.getValue();
				// 这里会生成一个Bean的名字,放到缓存中的是没有Bean的名字的
				autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
				if (requiredType.isInstance(autowiringValue)) {
					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
					break;
				}
			}
		}
		return result;
	}

               在此处生成了代理对象,在调用代理对象的方法时,通过ObjectFactoryDelegatingInvocationHandler的invoke方法得知,实际上是调用上述objectFactory的方法。

	public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
		if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
			ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
			if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
				//关键代码,在这里动态代理创建对象
				autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
						new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
			}
			else {
				return factory.getObject();
			}
		}
		return autowiringValue;
	}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			String methodName = method.getName();
			try {
				return method.invoke(this.objectFactory.getObject(), args);
			}
			catch (InvocationTargetException ex) {
				throw ex.getTargetException();
			}
		}

2.RequestObjectFactory

       这里我们先考虑下ResponseObjectFactory,RequestObjectFactory是如何注入的,在容器启动的过程中,在AbstractRefreshableWebApplicationContext的postProcessBeanFactory方法中,会将web请求相关的objectFactory类加入到容器中,准确的说是resolvableDependencies中。

	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		//BeanPostProcessor 的实现类,使用 ServletConfig 或者 ServletContext 类构造的 类;
		beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
		//实现该接口的类 希望 得到 ServletContext 的通知 ,即可以实时获取 ServletContext
		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
		//实现该接口的类 希望 得到 ServletConfig的通知 ,即可以实时获取 ServletConfig;
		beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

		//注册 请求域,session 域,应用域 以及 bean 工厂注册,便于在controller中直接获取
		WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
		WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
	}
	public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
			@Nullable ServletContext sc) {
		//registerResolvableDependency 该方法的主要作用就是指定该类型接口,如果外部要注入该类型接口的对象,则会注入我们指定的对象,而不会去管其他接口实现类
		beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
		beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
		beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
		beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
	}

        通过RequestObjectFactory的源码可以看到,getObject方法是从本地线程RequestContextHolder中获取,所以不同的请求处理线程会获取到不同的request对象。

	private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
		@Override
		public ServletRequest getObject() {
			return currentRequestAttributes().getRequest();
		}
	}
	private static ServletRequestAttributes currentRequestAttributes() {
		RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
		return (ServletRequestAttributes) requestAttr;
	}

        在每次请求的过程中,FrameworkServlet中的processRequest方法会调用initContextHolders方法,将request对象存储到requestAttributesHolder中,从而实现在线程本地中获取request。

	private void initContextHolders(HttpServletRequest request,
			@Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {

		if (localeContext != null) {
			LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
		}
		if (requestAttributes != null) {
			RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
		}
	}

总结

          在这里可以总结一下,首先在容器初始化的时候,会通过postProcessBeanFactory方法,在 resolvableDependencies中添加RequestObjectFactory对象,随后在controller对象的属性注入的时候,注入代理对象;在调用代理对象的方法时,会直接调用RequestObjectFactory的getObject方法对应对象的方法,而getObject方法会将当前请求request在threadlocal中取出;至于当前请求是在initContextHolders中将request放入到threadlocal中。        

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值