• struts2初始化探索(一)


    上篇文章已经介绍了struts2的简单使用,现在开始源码的学习。

    本篇主要介绍struts2的初始化。对应的源码为StrutsPrepareAndExecuteFilter中的init方法。

    先贴源码:

    public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter { //这里的StrutsStatics接口中没有方法,只有常量
        protected PrepareOperations prepare;
        protected ExecuteOperations execute;
        protected List<Pattern> excludedPatterns = null;
        public void init(FilterConfig filterConfig) throws ServletException {
            InitOperations init = new InitOperations(); 
            Dispatcher dispatcher = null; 
            try {
                FilterHostConfig config = new FilterHostConfig(filterConfig);
                init.initLogging(config);
                dispatcher = init.initDispatcher(config);
                init.initStaticContentLoader(config, dispatcher);
    
                prepare = new PrepareOperations(dispatcher);
                execute = new ExecuteOperations(dispatcher);
                this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
    
                postInit(dispatcher, filterConfig);
            } finally {
                if (dispatcher != null) {
                    dispatcher.cleanUpAfterInit();
                }
                init.cleanup();
            }
        }
    一个个对以上的对象跟方法进行分析:
    
    
    1. InitOperations init = new InitOperations(); --封装了一些初始化的操作
       源码中的大纲视图(具体方法下文会详细讲解):
    从这个视图我们可以发现,这个对象中封装的都是一些初始化的方法(从名字也不难发现),对照我们
    
    StrutsPrepareAndExecuteFilter中的init方法的源码,也可以得出相同的结论。
    
      2.FilterHostConfig config = new FilterHostConfig(filterConfig);
     --这里主要是对filterConfig进行了简单的封装
       源码如下:
        public class FilterHostConfig implements HostConfig {
        private FilterConfig config;
        public FilterHostConfig(FilterConfig config) {
            this.config = config;
        }
        public String getInitParameter(String key) {
            return config.getInitParameter(key);
        }
        public Iterator<String> getInitParameterNames() {
            return MakeIterator.convert(config.getInitParameterNames());
        }
        public ServletContext getServletContext() {
            return config.getServletContext();
        }
    }
      可以发现,这个对象只是对FiterConfig进行了简单的封装,
    
      getInitParameterNames(),这个方法,将枚举类型的参数换成了Iterator
    
    
    3.init.initLogging(config); --初始化日志记录器
    
    
     public void initLogging( HostConfig filterConfig ) {
            String factoryName = filterConfig.getInitParameter("loggerFactory");
            if (factoryName != null) {
                try {
                    Class cls = ClassLoaderUtil.loadClass(factoryName, this.getClass());
                    LoggerFactory fac = (LoggerFactory) cls.newInstance();
                    LoggerFactory.setLoggerFactory(fac);
                } catch ( InstantiationException e ) {
                    System.err.println("Unable to instantiate logger factory: " + factoryName + ", using default");
                    e.printStackTrace();
                } catch ( IllegalAccessException e ) {
                    System.err.println("Unable to access logger factory: " + factoryName + ", using default");
                    e.printStackTrace();
                } catch ( ClassNotFoundException e ) {
                    System.err.println("Unable to locate logger factory class: " + factoryName + ", using default");
                    e.printStackTrace();
                }
            }
        }
    4.dispatcher = init.initDispatcher(config);初始化转发器
    
        这个类是struts中很重要的一个类,它的工作就是将filter拦截到的请求转发
    
    struts2的请求处理模块。这句代码的作用是初始化一个转发器,或者叫分发器。
    
    源码如下:
    
     一:
      // 这部分代码,只是执行了创建了一个dispatcher跟执行dispatcher的init方法,并返回了一个对象,
      //  所以我们继续跟踪dcreateDispatcher跟ispatcher的init方法
    
     public Dispatcher initDispatcher( HostConfig filterConfig ) {
            Dispatcher dispatcher = createDispatcher(filterConfig);
            dispatcher.init();
            return dispatcher;
        }
    二:
     private Dispatcher createDispatcher( HostConfig filterConfig ) {
            Map<String, String> params = new HashMap<String, String>();
    
            for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
                String name = (String) e.next();
                String value = filterConfig.getInitParameter(name);
                params.put(name, value);
            }
            return new Dispatcher(filterConfig.getServletContext(), params);
        }
     
    三:
    源码如下:
     public void init() {
         if (configurationManager == null) {
          configurationManager = createConfigurationManager(DefaultBeanSelectionProvider.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);
                    }
                }
                
                 errorHandler.init(servletContext);
    
            } catch (Exception ex) {
                if (LOG.isErrorEnabled())
                    LOG.error("Dispatcher initialization failed", ex);
                throw new StrutsException(ex);
            }
        }
    由于篇幅原因,这篇文章中暂时不对这段代码做详细的解释,只做一些简单的注释,下篇文章专门解释这段代码
    

            5.init.initStaticContentLoader(config, dispatcher); --初始化静态资源加载器

            在完成对dispatcher对象的初始化后,strtus2维护的一个容器Container就创建完成了,可以使用了,

            这里通过dispatcher对象获取一个container的实例(container本身是一个接口),再通过containerd的

            getInstance方法获取了一个StaticContentLoader对象。

     public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) {
            StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
            loader.setHostConfig(filterConfig);
            return loader;
        }

            我们发现StaticContentLoader也是一个接口,继续看它声明的方法

            查阅大纲视图:

    再查找它的实现类DefaultStaticContentLoader

    (只有这一个实现类)

     public boolean canHandle(String resourcePath) {
            return serveStatic && (resourcePath.startsWith("/struts/") || resourcePath.startsWith("/static/"));
        }
    从这段代码中可以看出,只有请求路径中包含struts或者static时这个方法才会返回true
    

                实际上,在一般情况下strtus2是不会处理静态资源请求的,除非请求的路径是以struts或static开头,如

    有个test应用,那么请求必须是/test/struts/...或者/test/static/...这样才会处理。

    在StrutsPrepareAndExecuteFilter中的有如下代码:


    很明显,当判断为不需要处理时,会直接放行。

       6.       prepare = new PrepareOperations(dispatcher);  --实例化http请求预处理对象
                execute = new ExecuteOperations(dispatcher);  --示例化http请求处理对象

                    PrepareOperations和ExecuteOperations有什么用呢?和InitOperations类似,封装一些操作。只

    不过InitOperations是封装初始化的操作,而前两者则是封装请求预处理和请求处理的操作,当处理请求时方法

    被调用。先看PrepareOperations有哪些操作,查看源码大纲视图如下:

    其次是ExecuteOperations的源码,相对来说简单很多:

    public class ExecuteOperations {
    
        private Dispatcher dispatcher;
    
        @Deprecated
        public ExecuteOperations(ServletContext servletContext, Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
        }
    
        public ExecuteOperations(Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
        }
    
        /**
         * Tries to execute a request for a static resource
         * @return True if it was handled, false if the filter should fall through
         * @throws IOException
         * @throws ServletException
         */
        public boolean executeStaticResourceRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            // there is no action in this request, should we look for a static resource?
            String resourcePath = RequestUtils.getServletPath(request);
    
            if ("".equals(resourcePath) && null != request.getPathInfo()) {
                resourcePath = request.getPathInfo();
            }
    
            StaticContentLoader staticResourceLoader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
            if (staticResourceLoader.canHandle(resourcePath)) {
                staticResourceLoader.findStaticResource(resourcePath, request, response);
                // The framework did its job here
                return true;
    
            } else {
                // this is a normal request, let it pass through
                return false;
            }
        }
    
        /**
         * Executes an action
         * @throws ServletException
         */
        public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
            dispatcher.serviceAction(request, response, mapping);
        }
    }

    这里对这两段源码也不做详细讲解,下一节再细说。

            7.this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

            封装配置filter时指定的不处理的action请求的pattern成List<Pattern>,源码如下

        public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher ) {
            return buildExcludedPatternsList(dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN));
        }
                
        private List<Pattern> buildExcludedPatternsList( String patterns ) {
            if (null != patterns && patterns.trim().length() != 0) {
                List<Pattern> list = new ArrayList<Pattern>();
                String[] tokens = patterns.split(",");
                for ( String token : tokens ) {
                    list.add(Pattern.compile(token.trim()));
                }
                return Collections.unmodifiableList(list);
            } else {
                return null;
            }
        }
    
            8.postInit(dispatcher, filterConfig); --回调方法,用做用户拓展

            这个方法实际上什么都没做,源码如下:

              protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
              }

            9.init.cleanup();--垃圾清理

            源码如下:

    public void cleanup() {
            ActionContext.setContext(null);
            }
        public static void setContext(ActionContext context) {
            actionContext.set(context);
        }

        实际上就是将actionContext中的ActionContext对象置为null,我们跟踪actionContext这个对象发现,它其

    实是一个本地线程变量,所以这个操作实际上就是在清空线程中的ActionContext对象,这里不对这个对象做太

    多说明,接下来的文章会详细介绍。

    public class ActionContext implements Serializable {
    
        static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();
    

        源码的第一篇学习笔记就写到这。希望多多交流,有误的地方欢迎大家指正!




  • 相关阅读:
    隐藏NGINX服务器名称 和版本号
    salt-grains
    格式化输出文本的方法
    递归例子
    yield 生成器例子
    Python基础之函数
    Python基础之面向对象
    Python基础之模块2
    Python基础之字符编码
    Python基础之文件操作
  • 原文地址:https://www.cnblogs.com/daimzh/p/12854512.html
Copyright © 2020-2023  润新知