struts2 實現原理解析 此博文包含圖片 (2010-07-27 14:49:36)轉載▼ 標籤: filter dispatcher threadlocal actionproxy 雜談 分

struts2 實現原理解析

 (2010-07-27 14:49:36)
標籤: 

filter

 

dispatcher

 

threadlocal

 

actionproxy

 

雜談

分類: java和數據庫
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
struts2 <wbr>實現原理解析 

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);
                 }

  
發佈了1 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章