您的位置:首页 > 编程语言 > Java开发

struts2 实现原理解析

2011-12-24 17:59 302 查看


struts2 实现原理解析

struts2 操作 action servlet,是通过在web.xml中配置一个filter实现的
    <filter>

        <filter-name>struts2</filter-name>

        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>

     </filter>   

    <filter-mapping>

        <filter-name>struts2</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>
 
   注:现在新版本的struts2已经改成StrutsPrepareAndExecuteFilter,但原理大同小异,我们还按FilterDispatcher讲解
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>

  

而这个Filter FilterDispatcher 实际做了下列工作  

 public class FilterDispatcher implements StrutsStatics, Filter
1.filter的init()方法建立一个Dispatcher对象

以后struts2 都是围绕这个Dispatcher对象进行操作
init()方法将参数FilterConfig对象传给Dispatcher对象,实际就是将ServletContext对象传递给Dispatcher对象

而ServletContext包含了各种基本Servlet的运行环境,比如ServletContext提供了getAttribute(), setAttribute() 等方法

所以,实际是Dispatcher对象接管了基本Servlet的一切功能
public void init(FilterConfig filterConfig) throws ServletException {

        dispatcher = createDispatcher(filterConfig);

        ...

        }
 protected Dispatcher createDispatcher(FilterConfig filterConfig) {

        ...

        return new Dispatcher(filterConfig.getServletContext(), params);

    }
2.filter的doFilter()方法继续操作前面init()方法建立的作Dispatcher对象,将HttpServletRequest对象和HttpServletResponse对象传入Dispatcher中
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        HttpServletResponse response = (HttpServletResponse) res;

        ServletContext servletContext = getServletContext();

                ....

        dispatcher.serviceAction(request, response, servletContext, mapping);

    }
 

 Dispatcher对象是Struts2的核心操作对象,它主要实现实现了下面的工作
 1.它是线程安全的,即Dispatcher对象支持多线程,且每线程一副本
public class Dispatcher {

 private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();

 //Store the dispatcher instance for this thread.

  public static void setInstance(Dispatcher instance) {

     Dispatcher.instance.set(instance);

     // Tie the ObjectFactory threadlocal instance to this Dispatcher instance

              if (instance != null) {

         Container cont = instance.getContainer();

                  if (cont != null) {

             ObjectFactory.setObjectFactory(cont.getInstance(ObjectFactory.class));

         } else {

             LOG.warn("This dispatcher instance doesn't have a container, so the object factory won't be set.");

         }

     } else {

         ObjectFactory.setObjectFactory(null);

     }

 }

 //Provide the dispatcher instance for the current thread.

   public static Dispatcher getInstance() {

     return instance.get();

 }
2.上边说了,Dispatcher对象的建立/构造,是接受了参数FilterDispatcher过滤器的FilterConfig传来的ServletContext,这样才接管了基本Servlet的一切功能
private ServletContext servletContext;

private Map<String, String> initParams;

 public  Dispatcher(ServletContext servletContext, Map<String, String> initParams) {

     this.servletContext = servletContext;

     this.initParams = initParams;

 }
3. 上边说了,FilterDispatcher过滤器的doFilter()方法,调用了Dispatcher对象的serviceAction()方法,并把HttpServletRequest对象和HttpServletResponse对象传入

 这个serviceAction()方法,就是整个Strtus2的主引擎.

 serviceAction内部完成了多项功能:

配置文件加载,配置初始化

调用ActionProxy对象实现对Action类的执行

ActionProxy对象又会按照Struts2的Stack结构依次执行Inteceptor,action,method


 


public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping) throws ServletException {

 

     Map<String, Object> extraContext = createContextMap(request, response, mapping, context);

     // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action

     ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

        if (stack != null) {

         extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack));

     }

        try {

         String namespace = mapping.getNamespace();

         String name = mapping.getName();

         String method = mapping.getMethod();

         Configuration config = configurationManager.getConfiguration();

         ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(

                 namespace, name, extraContext, true, false);

         proxy.setMethod(method);

         request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

         // if the ActionMapping says to go straight to a result, do it!

          if (mapping.getResult() != null) {

             Result result = mapping.getResult();

             result.execute(proxy.getInvocation());

                 } else {

             proxy.execute();

                 }

         // If there was a previous value stack then set it back onto the request

            if (stack != null) {

             request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);

                 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息