Filter and Dispatcher

来源:互联网 发布:c语言入门教程pdf 编辑:程序博客网 时间:2024/06/06 06:30
使用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请求以及系统清理任务,贯穿了应用的完整的生命周期。
原创粉丝点击