Filter and Dispatcher

3 篇文章 0 订阅
使用Struts框架时,需要在web应用程序的web.xml文件中增加filter配置。如下代码
< filter >
       < filter-name >  struts </  filter-name >
       < filter-class >  org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter  </ filter-class >
</ filter >
web容器(如Tomcat)在加载应用的时候,会根据这里配置的filter标签,去实例化一个StrutsPrepareAndExecuteFilter对象,然后调用 StrutsPrepareAndExecuteFilter的 init方法做一些初始化的操作。 StrutsPrepareAndExecuteFilter实现了标准Filter接口。filter是由web容器调用的,在初次加载应用的时候会调用init方法来做一些初始化,在客户每次向web容器发送请求的时候,都会调用filter对象的doFilter方法。请求结束,就会调用destory方法。Filter机制很容易理解, StrutsPrepareAndExecuteFilter的init代码如下所示。
  StrutsPrepareAndExecuteFilter.init
public  void  init(FilterConfig filterConfig)  throws  ServletException {
        InitOperations init =  new  InitOperations();
         try  {
            FilterHostConfig config =  new  FilterHostConfig(filterConfig);
            init.initLogging(config);  //initialize the logger if it was configured
            Dispatcher dispatcher = init.initDispatcher(config);  //create a dispatcher, and initialize it
            init.initStaticContentLoader(config, dispatcher);

             prepare  =  new  PrepareOperations(filterConfig.getServletContext(), dispatcher);
             execute  =  new  ExecuteOperations(filterConfig.getServletContext(), dispatcher);
                       this . excludedPatterns  = init.buildExcludedPatternsList(dispatcher);
            postInit(dispatcher, filterConfig);
        }  finally  {
            init. cleanup();
        }
    }
FilterHostConfig对FilterConfig实现了包装,个人理解是为了适应struts而来,但在功能上几乎未作变动。初始化所作的事情主要涉及到三个元素:PrepareOperations、ExecuteOperations和Dispatcher。prepare的类型是  org.apache.struts2.dispatcher.ng. PrepareOperations,包括在一个请求在真正被执行前所要做的动作。execute的类型是  org.apache.struts2.dispatcher.ng.ExecuteOperations,包括了filter中所要执行的全部操作。

看这里的init方法,主要做的事情就是初始化日子系统(initLogging),初始化Dispatcher对象,然后就是对prepare和execute对象的初始化。 这两个类都容易理解,难点是Dispatcher的引入。在initDispatcher方法调用中,首先创建一个dispatcher对象,然后调用这个dispatcher对象的初始化方法。创建dispatcher对象的内容很简单,取出request请求中的参数和上下文,新建一个dispatcher对象,但在init方法中,则做了大量的事情。Dispatcher.java中init函数代码如下
  public  void  init() {

        if  ( configurationManager  ==  null ) {
                configurationManager  = createConfigurationManager(BeanSelectionProvider. DEFAULT_BEAN_NAME );
       }

         try  {
            init_FileManager();
            init_DefaultProperties();  // [1]
            init_TraditionalXmlConfigurations();  // [2]
            init_LegacyStrutsProperties();  // [3]
            init_CustomConfigurationProviders();  // [5]
            init_FilterInitParameters() ;  // [6]
            init_AliasStandardObjects() ;  // [7]

            Container container = init_PreloadConfiguration();//在这里,配置对象会重新加载容器
            container.inject(  this );
            init_CheckWebLogicWorkaround(container);

             if  (! dispatcherListeners  .isEmpty()) {
                 for  (DispatcherListener l :  dispatcherListeners ) {
                    l.dispatcherInitialized(  this );
                }
            }
        }  catch  (Exception ex) {
             if  ( LOG  .isErrorEnabled())
                 LOG .error( "Dispatcher initialization failed"  , ex);
             throw  new  StrutsException(ex);
        }
    }
Dispatcher对象初始化的时候要做哪些工作呢?首先初始化一个配置管理器对象configurationManager。然后是初始化各种形式的配置加载方式,通过configuratoinManager来将这些配置加载方式保存起来,像init_FileManager初始化文件管理器、init_DefaultProperties初始化default.properties的加载方式、init_TraditionalXmlConfiguration初始化struts-default.xml、struts.xml、struts-plugin.xml的加载方式,这里只是定义了配置的加载方式,但是并没有真正执行配置文件的加载。 再然后通过init_PreloadConfiguration初始化容器和初始化配置对象configuration,并且会将前面configurationManager保存的初始化的配置项的加载方式添加到configurationManager包含的配置对象configuration中去,实现容器的依赖注入。那么,一个配置对象configuration中所包含的内容有哪些呢?从DefaultConfiguration类中声明的相关成员变量可以略知一二。
protected   static  final  Logger  LOG  = LoggerFactory.getLogger(DefaultConfiguration.  class  );


     // Programmatic Action Configurations
     protected  Map<String, PackageConfig>  packageContexts   new  LinkedHashMap<String, PackageConfig>();
     protected  RuntimeConfiguration  runtimeConfiguration  ;
     protected  Container  container  ;
     protected  String  defaultFrameworkBeanName  ;
     protected  Set<String>  loadedFileNames   new  TreeSet<String>();
     protected  List<UnknownHandlerConfig>  unknownHandlerStack  ;


    ObjectFactory  objectFactory ;

最后通过init_CheckWebLogicWorkaround来检查是否需要支持WebLogic服务器的特殊设置。

通过这样的一段dispatcher对象的初始化动作,实现了对配置的加载、容器的注入和一些服务项的设置,也就是说通过dispatcher完成了资源的初始化、容器和服务之间的关联关系。


StrutsPrepareAndExecuteFilter初始化在应用加载的时候被调用一次,初始化了dispatcher对象,并且通过dispatcher对象完成了配置项的初始化、容器关联等。在每次接收请求的时候,就doFilter方法就会被调用。doFilter的代码如下所示
    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);
        }
    }
如果请求的URL在当前这个filter所负责的模式之外,就把这个请求传递给下一个filter链。否则,就对这个请求进行处理。请求进行处理通过execute.executeAction来完成。ExecuteOperations类的executeAction方法代码如下所示
public   void  executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)  throws   ServletException {
         dispatcher  .serviceAction(request, response,  servletContext  , mapping);
    }
所以,真正的任务的执行要是要通过dispatcher来完成。

应用结束后,会调用 StrutsPrepareAndExecuteFilter的destroy方法,通过调用prepare.cleanupDispatcher()。PrepareOperations类的cleanupDispatcher函数代码如下
public   void  cleanupDispatcher() {
         if  ( dispatcher  ==  null ) {
             throw   new  StrutsException(  "Something is seriously wrong, Dispatcher is not initialized (null) " );
        }  else  {
             try  {
                 dispatcher  .cleanup();
            }  finally  {
                ActionContext. setContext(  null );
            }
        }
    }
最后还是由dispatcher对象完成真正的请求动作。


综上来看,Dispatcher在框架中起到了核心作用,它是Struts2框架的核心分发器,它的职责涉及到系统的初始化、接收和预处理http请求以及系统清理任务,贯穿了应用的完整的生命周期。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值