Struts2值栈ValueStack源码阅读笔记

来源:互联网 发布:锁机软件下载 编辑:程序博客网 时间:2024/05/16 07:24

我们要从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之间的信息是怎样交互的?他们之间的类型转换是怎样完成的?留待后续完成。

0 0