webx 中request 对象作为单例注入的实现

一、介绍

webx 文档中描述:
你不能把一个短期的对象如request、response和request context注入到MyAction这个singleton对象。然而,在Webx中,这样做是可以的!奥秘在于Request Contexts服务对上表所列的这些短期对象作了特殊的处理,使它们可以被注入到singleton对象中。事实上,被注入的只是一个“空壳”,真正的对象是在被访问到的时候才会从线程中取得的。http://openwebx.org/docs/filter.html

1public class MyAction {
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HttpServletResponse response;

    @Autowired
    private ParserRequestContext parser;
}

二、现象验证&分析

2public 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 对象是一个单例的对象。

多次请求 request 对象的id 一直是624
2、我们观察request.getParameter(xxx)执行时的,线程堆栈情况,如下,在执行getParameter(xxx) 首先碰到了一个拦截器SpringExtUtil$ProxiedInterceptor, 这里拦截器通过com.alibaba.citrus.service.requestcontext.impl.RequestContextBeanFactoryPostProcessor$RequestProxyTargetFactory.getObject()从ThreadLocal中获取到真正的request对象。
执行request.getParameter是的线程栈

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;
        }
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值