Struts2值栈ValueStack源码阅读笔记

我们要从ActionContext开始说起,首先看StrutsPrepareAndExecuteFilter核心过滤器,也是整个程序的入口,doFilter()方法中的 ——->
prepare.createActionContext(request, response);

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            prepare.setEncodingAndLocale(request, response);
            prepare.createActionContext(request, response);
            prepare.assignDispatcherToThread();
            if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
                chain.doFilter(request, response);
            } else {
                request = prepare.wrapRequest(request);
                ActionMapping mapping = prepare.findActionMapping(request, response, true);
                if (mapping == null) {
                    boolean handled = execute.executeStaticResourceRequest(request, response);
                    if (!handled) {
                        chain.doFilter(request, response);
                    }
                } else {
                    execute.executeAction(request, response, mapping);
                }
            }
        } finally {
            prepare.cleanupRequest(request);
        }
    }

进入PrepareOpreration类的createActionContext()方法。

   public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
        ActionContext ctx;
        Integer counter = 1;
        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
        if (oldCounter != null) {
            counter = oldCounter + 1;
        }

        ActionContext oldContext = ActionContext.getContext();
        //如果ActionContext 不为null的话,重新new一个,在这里我们也可看到,ActionContext的数据结构,HashMap,用于查询最快的集合类。这段代码的意义在于使每一次请求,每一个action,都有其对应的ActionContext 
        if (oldContext != null) {
            // detected existing context, so we are probably in a forward
            ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
        } else {
        //如果为null通过IoC容器ContainerImpl中的getInstance()方法创建对应实例,值栈在这里创建完成
            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
//创建一个名字叫做extraContext的Map,里面存储了request,response,servletContext信息,并将其放入ActionContext
     stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
            ctx = new ActionContext(stack.getContext());
        }
        request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
        ActionContext.setContext(ctx);
        return ctx;
    }

在上面的注释中,我们提到ActionContext的数据结构是HashMap,那么ValueStack的数据结构是怎样的?

进入createValueStack()方法,进入OgnlValueStackFactory类,这个类继承ValueStackFactory接口

public class OgnlValueStackFactory implements ValueStackFactory 

进入ValueStackFactory 接口中发现,这个接口就是用来创建值栈的。


public interface ValueStackFactory {


    ValueStack createValueStack();


    ValueStack createValueStack(ValueStack stack);

}

回到OgnlValueStackFactory,找到createValueStack()方法.

    public ValueStack createValueStack() {
        ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, allowStaticMethodAccess);
        container.inject(stack);
        stack.getContext().put(ActionContext.CONTAINER, container);
        return stack;
    }

进入OgnlValueStack的构造方法之中

  protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticAccess) {
        setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticAccess);
        push(prov);
    }

发现构造方法是protected 修饰符,我认为是确保了安全性,进入setRoot()方法。

  protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot,
                           boolean allowStaticMethodAccess) {
        //栈对象是一个CompountRoot类型的栈结构
        this.root = compoundRoot;
        //设定OGNL所需的MemeberAccess实现类
        this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);
        //创建OGNL的上下文
        this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess);
        context.put(VALUE_STACK, this);
        Ognl.setClassResolver(context, accessor);
        ((OgnlContext) context).setTraceEvaluations(false);
        ((OgnlContext) context).setKeepLastEvaluation(false);
    }

这才是真正的OgnlValueStack的初始化过程,我们接下来进入CompoundRoot类

public class CompoundRoot extends ArrayList {

    public CompoundRoot() {
    }

    public CompoundRoot(List list) {
        super(list);
    }


    public CompoundRoot cutStack(int index) {
        return new CompoundRoot(subList(index, size()));
    }

    public Object peek() {
        return get(0);
    }

    public Object pop() {
        return remove(0);
    }

    public void push(Object o) {
        add(0, o);
    }
}

发现这个类继承了ArrayList类,我们发现其实OgnlValueStack的底层实际上是通过链表实现的栈结构。
接下来,我们要往回走,回到OgnlValueStackFactory的createValueStack()方法

public ValueStack createValueStack() {
        ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, allowStaticMethodAccess);
        //将返回的值栈对象注入容器
        container.inject(stack);
        //将容器存入上下文,也就是ActionContext
        stack.getContext().put(ActionContext.CONTAINER, container);
        return stack;
    }

到这里ActionContext和值栈的初始化过程,以及他们之间的关系似乎已经弄清楚了,借用一张网上的图来说明他们之间的关系。

这里写图片描述

学习了值栈以后,引发了我的思考,xwork与ognl之间的信息是怎样交互的?他们之间的类型转换是怎样完成的?留待后续完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值