一、介绍
webx 文档中描述:
你不能把一个短期的对象如request、response和request context注入到MyAction这个singleton对象。然而,在Webx中,这样做是可以的!奥秘在于Request Contexts服务对上表所列的这些短期对象作了特殊的处理,使它们可以被注入到singleton对象中。事实上,被注入的只是一个“空壳”,真正的对象是在被访问到的时候才会从线程中取得的。http://openwebx.org/docs/filter.html
例1、
public class MyAction {
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
@Autowired
private ParserRequestContext parser;
}
二、现象验证&分析
例2、
public class ManagerHsf {
@Resource
HttpServletRequest request;
@Resource
private HankService hankService;
问题来了, 这个request 的空壳是如何实现,执行request.getParameter(xxx), request.setParameter(xxx)时,到真正的request中取值的。
1、注入的request对象 是HttpServletRequest$$EnhancerByCGLIB$$56fdd100
类的一个实例, 重复多次http请求,发现这个对象的id 始终不变,都是624, 显然这里注入的request 对象是一个单例的对象。
2、我们观察request.getParameter(xxx)执行时的,线程堆栈情况,如下,在执行getParameter(xxx) 首先碰到了一个拦截器SpringExtUtil$ProxiedInterceptor, 这里拦截器通过com.alibaba.citrus.service.requestcontext.impl.RequestContextBeanFactoryPostProcessor$RequestProxyTargetFactory.getObject()
从ThreadLocal中获取到真正的request对象。
public class RequestContextBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private static class RequestProxyTargetFactory implements ProxyTargetFactory {
public Object getObject() {
RequestAttributes requestAttrs = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) requestAttrs).getRequest();
return request;
}
}
....
}
public abstract class RequestContextHolder {
private static final ThreadLocal requestAttributesHolder = new NamedThreadLocal("Request attributes");
private static final ThreadLocal inheritableRequestAttributesHolder =
new NamedInheritableThreadLocal("Request context");
public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
RequestAttributes attributes = getRequestAttributes();
return attributes;
}
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = (RequestAttributes) requestAttributesHolder.get();
if (attributes == null) {
attributes = (RequestAttributes) inheritableRequestAttributesHolder.get();
}
return attributes;
......
}
从上面代码中有两个ThreadLocal 对象, 真正的request 对象, 是通过, RequestContextHolder的静态方法,获取得到,当前线程关联的 ”ServletRequestAttributes“对象, 而获取到的。
三、实现原理
实现的代码集中在RequestContextBeanFactoryPostProcessor 中, 在方法postProcessBeanFactory 中往beanFactory 中注册了3个单例的bean, (HttpServletRequest, HttpSession和HttpServletResponse), 以及一组RequestContext的单例bean.
register方法中是调用的beanFactory.registerResolvableDependency(intfs, instance);
这个方法能注释“ Register a special dependency type with corresponding autowired value.”。
以 register( beanFactory, ServletRequest.class,createProxy(HttpServletRequest.class, beanFactory.getBeanClassLoader(), new RequestProxyTargetFactory()));
为例,也就是所有HttpServletRequest 类型的依赖,都能被自动注入。
再看createProxy方法,实际执行的时候,是通过RequestProxyTargetFactory.getObject()获取被代理的原始对象, 然后在这基础上执行方法。
/*
* Copyright 2010 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.alibaba.citrus.service.requestcontext.impl;
import static com.alibaba.citrus.springext.util.SpringExtUtil.*;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.citrus.service.requestcontext.RequestContext;
import com.alibaba.citrus.service.requestcontext.RequestContextChainingService;
import com.alibaba.citrus.service.requestcontext.RequestContextInfo;
import com.alibaba.citrus.service.requestcontext.util.RequestContextUtil;
import com.alibaba.citrus.springext.util.ProxyTargetFactory;
/**
* 创建全局的request context对象,以及request、response对象。
* <p>
* 无论是何种bean都可以注入这些对象:request context、request、response。
* </p>
*
* @author Michael Zhou
*/
public class RequestContextBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private final static Logger log = LoggerFactory.getLogger(RequestContextBeanFactoryPostProcessor.class);
private final String requestContextsName;
public RequestContextBeanFactoryPostProcessor(String requestContextsName) {
this.requestContextsName = requestContextsName;
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 先注册request/response/session,再从beanFactory中取得requestContexts。
// 创建全局的request实例。
register(
beanFactory,
ServletRequest.class,
createProxy(HttpServletRequest.class, beanFactory.getBeanClassLoader(), new RequestProxyTargetFactory()));
// 创建全局的session实例。
register(beanFactory, HttpSession.class,
createProxy(HttpSession.class, beanFactory.getBeanClassLoader(), new SessionProxyTargetFactory()));
// 创建全局的response实例。
register(
beanFactory,
ServletResponse.class,
createProxy(HttpServletResponse.class, beanFactory.getBeanClassLoader(),
new ResponseProxyTargetFactory()));
// 取得requestContexts时会激活requestContexts的初始化。
// 由于request/response/session已经被注册,因此已经可被注入到requestContexts的子对象中。
RequestContextChainingService requestContexts = (RequestContextChainingService) beanFactory.getBean(
requestContextsName, RequestContextChainingService.class);
// 创建全局的request context实例。
for (RequestContextInfo<?> info : requestContexts.getRequestContextInfos()) {
Class<? extends RequestContext> requestContextInterface = info.getRequestContextInterface();
Class<? extends RequestContext> requestContextProxyInterface = info.getRequestContextProxyInterface();
// 避免对没有子接口的request context对象创建proxy,否则没有意义。
if (!RequestContext.class.equals(requestContextProxyInterface)) {
register(
beanFactory,
requestContextInterface,
createProxy(requestContextProxyInterface, beanFactory.getBeanClassLoader(),
new RequestContextProxyTargetFactory(requestContextProxyInterface)));
}
}
}
private void register(ConfigurableListableBeanFactory beanFactory, Class<?> intfs, Object instance) {
beanFactory.registerResolvableDependency(intfs, instance);
log.debug("Registered Global Proxy for interface {}", intfs.getName());
}
private static class RequestProxyTargetFactory implements ProxyTargetFactory {
public Object getObject() {
RequestAttributes requestAttrs = RequestContextHolder.currentRequestAttributes();
if (!(requestAttrs instanceof ServletRequestAttributes)) {
throw new IllegalStateException("Current request is not a servlet request");
}
HttpServletRequest request = ((ServletRequestAttributes) requestAttrs).getRequest();
if (request == null) {
throw new IllegalStateException("Current request is not a servlet request");
}
return request;
}
}
private final class ResponseProxyTargetFactory extends RequestProxyTargetFactory {
@Override
public Object getObject() {
HttpServletRequest request = (HttpServletRequest) super.getObject();
RequestContext requestContext = RequestContextUtil.getRequestContext(request);
if (requestContext == null) {
throw new IllegalStateException("Current request does not support request context");
}
return requestContext.getResponse();
}
}
private final class SessionProxyTargetFactory extends RequestProxyTargetFactory {
@Override
public Object getObject() {
HttpServletRequest request = (HttpServletRequest) super.getObject();
RequestContext requestContext = RequestContextUtil.getRequestContext(request);
if (requestContext == null) {
throw new IllegalStateException("Current request does not support request context");
}
return requestContext.getRequest().getSession();
}
}
private final class RequestContextProxyTargetFactory extends RequestProxyTargetFactory {
private final Class<? extends RequestContext> requestContextInterface;
private RequestContextProxyTargetFactory(Class<? extends RequestContext> requestContextInterface) {
this.requestContextInterface = requestContextInterface;
}
@Override
public Object getObject() {
HttpServletRequest request = (HttpServletRequest) super.getObject();
RequestContext requestContext = RequestContextUtil.findRequestContext(request, requestContextInterface);
if (requestContext == null) {
throw new IllegalStateException("Current request does not support request context: "
+ requestContextInterface.getName());
}
return requestContext;
}
}
}