Struts2源码浅析-初始化

StrutsPrepareAndExecuteFilter实现了Filter接口  init方法为初始化入口
StrutsPrepareAndExecuteFilter init方法
public void init(FilterConfig filterConfig) throws ServletException {  
    //初始化辅助类 类似一个Delegate  
     InitOperations init = new InitOperations();  
     try {  
        // FilterHostConfig 封装了FilterConfig参数对象   
         FilterHostConfig config = new FilterHostConfig(filterConfig);  
         //LoggerFactory配置加载   
         //如果没有web.xml 没有配置“loggerFactory”参数  尝试org.apache.commons.logging.LogFactory  
         //如果失败 使用JdkLoggerFactory  
         //TODO SPI  
         init.initLogging(config);  
         //TODO 创建Dispatcher 注册加载器   执行加载器  创建容器 解析xml    
         Dispatcher dispatcher = init.initDispatcher(config);  
         init.initStaticContentLoader(config, dispatcher);  
         //预处理类 请求处理时才会真正用到  
         //1.主要负责在每次请求 创建ActionContext 清除ActionContext  
         //2.当接收到一个请求时 通过uri查找 ActionConfig 创建ActionMapping  
         prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);  
         //处理请求  Delegate  
         execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);  
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);  
//空实现 留作扩展  
         postInit(dispatcher, filterConfig);  
     } finally {  
         init.cleanup();  
     }  
 }  

InitOperations 类似与一个Delegate 主要负责实例化Dispatche  再把初始化操作转交给Dispatche init处理

public Dispatcher initDispatcher( HostConfig filterConfig ) {  
    //创建Dispatcher  
    Dispatcher dispatcher = createDispatcher(filterConfig);  
    //核心方法  Container容器的创建   xml解析在此方法发生  
    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);  
}  

Dispatcher init方法  1.针对配置文件 注册不同的加载器 保存到ConfigurationManager类中的一个变量中  2.创建容器 解析xml

public void init() {  
    //创建配置操作管理类  ,  会保存元素加载器   
    if (configurationManager == null) {  
        configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);  
    }  
       try {  
        /**初始化各种形式加载器,保存到ConfigurationManager#containerProviders Map集合中 没有真正执行加载 解析逻辑*/  
          
        //org/apache/struts2/default.properties属性文件  里面定义了一系列struts常量  
           init_DefaultProperties(); // [1]  
             
           //web.xml配置的 config参数 [配置多个用","分开]  
           //如果没有该参数 默认为 struts-default.xml[框架级],struts-plugin.xml[框架级],struts.xml[系统级别]  
           //根据文件名称 创建加载器  加载xml主要有一下两个解析器  
           //XmlConfigurationProvider[xwork.xml],  
           //StrutsXmlConfigurationProvider[struts相关配置文件]配置元素加载器   
           init_TraditionalXmlConfigurations(); // [2]  
             
           //struts.locale 注册  
           init_LegacyStrutsProperties(); // [3]  
             
           //实例化  我们自定义的加载器  保存到containerProviders集合中  
           // web.xml configProviders参数  多个用","分开  配置器必须是ConfigurationProvider接口的实例  
           //TODO SPI  
           init_CustomConfigurationProviders(); // [5]  
             
           //web.xml配置的init-param参数 加载器  最终会保存到Container容器中  
           init_FilterInitParameters() ; // [6]  
             
           //TODO 根据我们在struts.xml定义的 常量 选择插件类     
           //比如集成spring 会用到org.apache.struts2.spring.StrutsSpringObjectFactory   
           init_AliasStandardObjects() ; // [7]  
             
           /** 执行加载器 */  
           //TODO 创建容器  解析xml  真正执行加载器方法   
           Container container = init_PreloadConfiguration();  
           //执行当前Dispatcher对象 依赖关系注入   
           container.inject(this);  
             
           //额外动作   
           init_CheckConfigurationReloading(container);  
           init_CheckWebLogicWorkaround(container);  
  
       } catch (Exception ex) {  
           if (LOG.isErrorEnabled())  
               LOG.error("Dispatcher initialization failed", ex);  
           throw new StrutsException(ex);  
       }  
   }  

ConfigurationManager 主要管理 创建的各种加载器

public class ConfigurationManager {  
  
    protected static final Logger LOG = LoggerFactory.getLogger(ConfigurationManager.class);  
    //配置元素管理器  
    protected Configuration configuration;  
      
    protected Lock providerLock = new ReentrantLock();  
    //创建的xml加载器会保存到次集合中  
    private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<ContainerProvider>();  
      
} 

Dispatcher的 createConfigurationManager方法

protected ConfigurationManager createConfigurationManager(String name) {  
    //name - >  struts  
    return new ConfigurationManager(name);  
}  

1.default.properties 属性文件加载器

private void init_DefaultProperties() {  
    //保存到ConfigurationManager加载器集合中  
    configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());  
}  

2.创建struts相关文件加载器 StrutsXmlConfigurationProvider

private void init_TraditionalXmlConfigurations() {  
    //web.xml 配置的config  
    String configPaths = initParams.get("config");  
    if (configPaths == null) {  
        //如果没有配置  默认 struts-default.xml,struts-plugin.xml,struts.xml  
        configPaths = DEFAULT_CONFIGURATION_PATHS;  
    }  
    String[] files = configPaths.split("\\s*[,]\\s*");  
    for (String file : files) {  
        if (file.endsWith(".xml")) {  
            if ("xwork.xml".equals(file)) {  
                configurationManager.addConfigurationProvider(createXmlConfigurationProvider(file, false));  
            } else {  
                //struts xml加载器    
                //StrutsXmlConfigurationProvider  
                configurationManager.addConfigurationProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));  
            }  
        } else {  
            throw new IllegalArgumentException("Invalid configuration file name");  
        }  
    }  
}  
  
protected XmlConfigurationProvider createXmlConfigurationProvider(String filename, boolean errorIfMissing) {  
    return new XmlConfigurationProvider(filename, errorIfMissing);  
}  
  
protected XmlConfigurationProvider createStrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {  
    return new StrutsXmlConfigurationProvider(filename, errorIfMissing, ctx);  
}  

3.web.xml扩展的ContainerProviders加载器 实例化

private void init_CustomConfigurationProviders() {  
    //web.xml 中configProviders 节点  
    String configProvs = initParams.get("configProviders");  
    if (configProvs != null) {  
        String[] classes = configProvs.split("\\s*[,]\\s*");  
        for (String cname : classes) {  
         Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());  
         ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();  
         configurationManager.addConfigurationProvider(prov);  
        }  
    }  
}  

init_PreloadConfiguration 方法主要完成创建容器, 解析xml动作

private Container init_PreloadConfiguration() {  
    //创建Container  解析xml  
    Configuration config = configurationManager.getConfiguration();  
    Container container = config.getContainer();  
  
    boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));  
    LocalizedTextUtil.setReloadBundles(reloadi18n);  
    return container;  
}  

init_PreloadConfiguration 方法中调用了  ConfigurationManager的getConfiguration 方法

public synchronized Configuration getConfiguration() {  
    //创建配置元素管理器  
    if (configuration == null) {  
        // defaultFrameworkBeanName  - > struts  
        setConfiguration(createConfiguration(defaultFrameworkBeanName));  
        try {  
            // getContainerProviders  返回注册的各种加载器   
            // reloadContainer  创建Container  解析xml  
            configuration.reloadContainer(getContainerProviders());  
        } catch (ConfigurationException e) {  
            setConfiguration(null);  
            throw new ConfigurationException("Unable to load configuration.", e);  
        }  
    } else {  
        conditionalReload();  
    }  
    return configuration;  
}  


protected Configuration createConfiguration(String beanName) {  
    return new DefaultConfiguration(beanName);  
}  

DefaultConfiguration的reloadContainer方法 会去执行已注册的各种加载器 ,和创建容器

public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {  
        packageContexts.clear();  
        loadedFileNames.clear();  
        List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();  
        // 保存struts常量  
        ContainerProperties props = new ContainerProperties();  
        //容器构建器  
        ContainerBuilder builder = new ContainerBuilder();  
        for (final ContainerProvider containerProvider : providers) {  
            /** 
             * 初始化Document 准备解析 
             * 具体在XmlConfigurationProvider实现类 会处理include节点  
             * 处理完成之后Document会保存到XmlConfigurationProvider#documents list集合中 
             * include file路径会保存到XmlConfigurationProvider#loadedFileUrls set集合中  
             * 从代码中发现 include file属性中 可以使用通配符 "*" 
             */  
            /** StrutsXmlConfigurationProvider 是 XmlConfigurationProvider的子类 */  
            /** StrutsXmlConfigurationProvider struts*.xml */  
            containerProvider.init(this);  
            //针对"bean","constant","unknown-handler-stack"节点  不包括"package"节点   解析xml   
            //每一个bean 对应一个LocatableFactory  LocatableFactory保存了bean的定义  
            //bean定义 保存到ContainerBuilder#factories map集合中   
            //配置文件中定义的常量  保存到props中  
            containerProvider.register(builder, props);  
        }  
        //将常量保存到ContainerBuilder#factories map集合中   
        //每一个常量对应一个LocatableConstantFactory  
        props.setConstants(builder);  
        builder.factory(Configuration.class, new Factory<Configuration>() {  
            public Configuration create(Context context) throws Exception {  
                return DefaultConfiguration.this;  
            }  
        });  
  
        ActionContext oldContext = ActionContext.getContext();  
        try {  
            //创建辅助容器 ContainerImpl并且 实例化 struts一些核心类   
            Container bootstrap = createBootstrapContainer();  
            setContext(bootstrap);  
              
            //主容器 这是一个全局变量   
            container = builder.create(false);  
            setContext(container);  
            objectFactory = container.getInstance(ObjectFactory.class);  
  
            // Process the configuration providers first  
            for (final ContainerProvider containerProvider : providers) {  
                if (containerProvider instanceof PackageProvider) {  
                    //com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#setObjectFactory(ObjectFactory)  
                    container.inject(containerProvider);  
                    //解析  xml  package节点  
                    //保存packageContexts map集合中  
                    //com.opensymphony.xwork2.config.providers.XmlConfigurationProvider  line 481  
                    ((PackageProvider) containerProvider).loadPackages();  
                    packageProviders.add((PackageProvider) containerProvider);  
                }  
            }  
  
            // Then process any package providers from the plugins  
            Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);  
            if (packageProviderNames != null) {  
                for (String name : packageProviderNames) {  
                    PackageProvider provider = container.getInstance(PackageProvider.class, name);  
                    provider.init(this);  
                    provider.loadPackages();  
                    packageProviders.add(provider);  
                }  
            }  
            //TODO  
            rebuildRuntimeConfiguration();  
        } finally {  
            if (oldContext == null) {  
                ActionContext.setContext(null);  
            }  
        }  
        return packageProviders;  
    }  

StrutsXmlConfigurationProvider的init方法 具体在父类XmlConfigurationProvider中实现

public void init(Configuration configuration) {  
    this.configuration = configuration;  
    this.includedFileNames = configuration.getLoadedFileNames();  
    // configFileName ->struts.xml  
    //1.递归处理include节点  
    //2.生成Document 集合  
    loadDocuments(configFileName);  
}  

loadDocuments方法中调用了loadConfigurationFiles方法  返回一个Document集合

private void loadDocuments(String configFileName) {  
    loadedFileUrls.clear();  
     //List<Document> documents  
    documents = loadConfigurationFiles(configFileName, null);  
} 

loadConfigurationFiles方法 递归处理include节点 最终生成Document集合

private List<Document> loadConfigurationFiles(String fileName, Element includeElement) {  
        List<Document> docs = new ArrayList<Document>();  
        List<Document> finalDocs = new ArrayList<Document>();  
        //防止include重复引入  
        if (!includedFileNames.contains(fileName)) {  
            if (LOG.isDebugEnabled()) {  
                LOG.debug("Loading action configurations from: " + fileName);  
            }  
            includedFileNames.add(fileName);  
            Iterator<URL> urls = null;  
            InputStream is = null;  
            IOException ioException = null;  
            try {  
                urls = getConfigurationUrls(fileName);  
            } catch (IOException ex) {  
                ioException = ex;  
            }  
  
            if (urls == null || !urls.hasNext()) {  
                if (errorIfMissing) {  
                    throw new ConfigurationException("Could not open files of the name " + fileName, ioException);  
                } else {  
                    LOG.info("Unable to locate configuration files of the name " + fileName + ", skipping");  
                    return docs;  
                }  
            }  
            URL url = null;  
            while (urls.hasNext()) {  
                try {  
                    url = urls.next();  
                    is = FileManager.loadFile(url);  
                    InputSource in = new InputSource(is);  
                    in.setSystemId(url.toString());  
                    //生成Document对象  
                    docs.add(DomHelper.parse(in, dtdMappings));  
                } catch (XWorkException e) {  
                    if (includeElement != null) {  
                        throw new ConfigurationException("Unable to load " + url, e, includeElement);  
                    } else {  
                        throw new ConfigurationException("Unable to load " + url, e);  
                    }  
                } catch (Exception e) {  
                    final String s = "Caught exception while loading file " + fileName;  
                    throw new ConfigurationException(s, e, includeElement);  
                } finally {  
                    if (is != null) {  
                        try {  
                            is.close();  
                        } catch (IOException e) {  
                            LOG.error("Unable to close input stream", e);  
                        }  
                    }  
                }  
            }  
            //sort the documents, according to the "order" attribute  
            Collections.sort(docs, new Comparator<Document>() {  
                public int compare(Document doc1, Document doc2) {  
                    return XmlHelper.getLoadOrder(doc1).compareTo(XmlHelper.getLoadOrder(doc2));  
                }  
            });  
            for (Document doc : docs) {  
                Element rootElement = doc.getDocumentElement();  
                NodeList children = rootElement.getChildNodes();  
                int childSize = children.getLength();  
                for (int i = 0; i < childSize; i++) {  
                    Node childNode = children.item(i);  
                    if (childNode instanceof Element) {  
                        Element child = (Element) childNode;  
                        final String nodeName = child.getNodeName();  
                        if ("include".equals(nodeName)) {  
                            String includeFileName = child.getAttribute("file");  
                            //可以使用通配符匹配    
                            if (includeFileName.indexOf('*') != -1) {  
                                ClassPathFinder wildcardFinder = new ClassPathFinder();  
                                wildcardFinder.setPattern(includeFileName);  
                                Vector<String> wildcardMatches = wildcardFinder.findMatches();  
                                for (String match : wildcardMatches) {  
                                    //递归处理include节点  
                                    finalDocs.addAll(loadConfigurationFiles(match, child));  
                                }  
                            } else {  
                                //递归处理include节点  
                                finalDocs.addAll(loadConfigurationFiles(includeFileName, child));  
                            }  
                        }  
                    }  
                }  
                finalDocs.add(doc);  
                loadedFileUrls.add(url.toString());  
            }  
        }  
        return finalDocs;  
    }  

StrutsXmlConfigurationProvider的register方法 主要在父类 XmlConfigurationProvider中实现
1.遍历init方法中生成的Document 集合  解析xml文件中定义的bean,constant常量节点 不会处理package节点
2.解析bean节点的值 包装成LocatableFactory对象  注册到ContainerBuilder中factories map集合中
3.解析constant节点的值 保存到ContainerProperties 对象中
XmlConfigurationProvider 的register  这里只解析 bean , constant节点

public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {  
    Map<String, Node> loadedBeans = new HashMap<String, Node>();  
    for (Document doc : documents) {  
        Element rootElement = doc.getDocumentElement();  
        NodeList children = rootElement.getChildNodes();  
        int childSize = children.getLength();  
        for (int i = 0; i < childSize; i++) {  
            Node childNode = children.item(i);  
            if (childNode instanceof Element) {  
                Element child = (Element) childNode;  
                final String nodeName = child.getNodeName();  
                //解析bean节点  
                if ("bean".equals(nodeName)) {  
                    String type = child.getAttribute("type");  
                    String name = child.getAttribute("name");  
                    String impl = child.getAttribute("class");  
                    String onlyStatic = child.getAttribute("static");  
                    String scopeStr = child.getAttribute("scope");  
                    boolean optional = "true".equals(child.getAttribute("optional"));  
                    Scope scope = Scope.SINGLETON;  
                    if ("default".equals(scopeStr)) {  
                        scope = Scope.DEFAULT;  
                    } else if ("request".equals(scopeStr)) {  
                        scope = Scope.REQUEST;  
                    } else if ("session".equals(scopeStr)) {  
                        scope = Scope.SESSION;  
                    } else if ("singleton".equals(scopeStr)) {  
                        scope = Scope.SINGLETON;  
                    } else if ("thread".equals(scopeStr)) {  
                        scope = Scope.THREAD;  
                    }  
                    if (StringUtils.isEmpty(name)) {  
                        name = Container.DEFAULT_NAME;  
                    }  
                    try {  
                        Class cimpl = ClassLoaderUtil.loadClass(impl, getClass());  
                        Class ctype = cimpl;  
                        if (StringUtils.isNotEmpty(type)) {  
                            ctype = ClassLoaderUtil.loadClass(type, getClass());  
                        }  
                        if ("true".equals(onlyStatic)) {  
                            // Force loading of class to detect no class def found exceptions  
                            cimpl.getDeclaredClasses();  
                            containerBuilder.injectStatics(cimpl);  
                        } else {  
                            // beanName + class 构成唯一约束   
                            if (containerBuilder.contains(ctype, name)) {  
                                //用loadedBeans map集合检查是否有重复配置的bean  
                                Location loc = LocationUtils.getLocation(loadedBeans.get(ctype.getName() + name));  
                                if (throwExceptionOnDuplicateBeans) {  
                                    throw new ConfigurationException("Bean type " + ctype + " with the name " + name + " has already been loaded by " + loc, child);  
                                }  
                            }  
                            // Force loading of class to detect no class def found exceptions  
                            cimpl.getDeclaredConstructors();  
  
                            if (LOG.isDebugEnabled()) {  
                                LOG.debug("Loaded type:" + type + " name:" + name + " impl:" + impl);  
                            }  
                            //LocatableFactory 类似spring中 BeanDefinition   
                            //bean定义 保存到ContainerBuilder#factories map集合中  
                            //目前为止  并未真正实例化bean  
                            containerBuilder.factory(ctype, name, new LocatableFactory(name, ctype, cimpl, scope, childNode), scope);  
                        }  
                        //loadedBeans 检查重复配置的bean  
                        loadedBeans.put(ctype.getName() + name, child);  
                    } catch (Throwable ex) {  
                        if (!optional) {  
                            throw new ConfigurationException("Unable to load bean: type:" + type + " class:" + impl, ex, childNode);  
                        } else {  
                            LOG.debug("Unable to load optional class: " + ex);  
                        }  
                    }  
                    //constant常量节点  
                } else if ("constant".equals(nodeName)) {  
                    String name = child.getAttribute("name");  
                    String value = child.getAttribute("value");  
                    //ContainerProperties ->props  
                    props.setProperty(name, value, childNode);  
                } else if (nodeName.equals("unknown-handler-stack")) {  
                    List<UnknownHandlerConfig> unknownHandlerStack = new ArrayList<UnknownHandlerConfig>();  
                    NodeList unknownHandlers = child.getElementsByTagName("unknown-handler-ref");  
                    int unknownHandlersSize = unknownHandlers.getLength();  
                    for (int k = 0; k < unknownHandlersSize; k++) {  
                        Element unknownHandler = (Element) unknownHandlers.item(k);  
                        unknownHandlerStack.add(new UnknownHandlerConfig(unknownHandler.getAttribute("name")));  
                    }  
                    if (!unknownHandlerStack.isEmpty()) configuration.setUnknownHandlerStack(unknownHandlerStack);  
                }  
            }  
        }  
    }  
}  

XmlConfigurationProvider的loadPackages方法  解析package节点下的所有子节点interceptor ,ResultType等等
保存到DefaultConfiguration packageContexts map集合中

public void loadPackages() throws ConfigurationException {  
        List<Element> reloads = new ArrayList<Element>();  
        for (Document doc : documents) {  
            Element rootElement = doc.getDocumentElement();  
            NodeList children = rootElement.getChildNodes();  
            int childSize = children.getLength();  
            for (int i = 0; i < childSize; i++) {  
                Node childNode = children.item(i);  
                if (childNode instanceof Element) {  
                    Element child = (Element) childNode;  
                    final String nodeName = child.getNodeName();  
                    if ("package".equals(nodeName)) {  
                        //解析package节点  包装成PackageConfig对象  
                        PackageConfig cfg = addPackage(child);  
                        if (cfg.isNeedsRefresh()) {  
                            reloads.add(child);  
                        }  
                    }  
                }  
            }  
            //空实现  扩展时用  
            loadExtraConfiguration(doc);  
        }  
  
        if (reloads.size() > 0) {  
            reloadRequiredPackages(reloads);  
        }  
        for (Document doc : documents) {  
            //空实现  扩展时用  
            loadExtraConfiguration(doc);  
        }  
        documents.clear();  
        configuration = null;  
    } 

package节点下的所有子节点

protected PackageConfig addPackage(Element packageElement) throws ConfigurationException {  
    PackageConfig.Builder newPackage = buildPackageContext(packageElement);  
    if (newPackage.isNeedsRefresh()) {  
        return newPackage.build();  
    }  
    //处理所有的ResultType 包括自定义的 , strust-default.xml中定义的  
    addResultTypes(newPackage, packageElement);  
    //interceptor节点  
    loadInterceptors(newPackage, packageElement);  
    //default-interceptor-ref  
    loadDefaultInterceptorRef(newPackage, packageElement);  
    //default-class-ref节点  
    loadDefaultClassRef(newPackage, packageElement);  
    //全局result global-results节点  
    loadGlobalResults(newPackage, packageElement);  
    //global-exception-mappings节点 异常处理   
    loadGobalExceptionMappings(newPackage, packageElement);  
  
    NodeList actionList = packageElement.getElementsByTagName("action");  
    for (int i = 0; i < actionList.getLength(); i++) {  
        Element actionElement = (Element) actionList.item(i);  
        // action节点 result节点处理  
        addAction(actionElement, newPackage);  
    }  
    //default-action-ref  
    loadDefaultActionRef(newPackage, packageElement);  
    PackageConfig cfg = newPackage.build();  
    //TODO 保存到Map<string packageconfig=""> packageContexts 集合中  
    configuration.addPackageConfig(cfg.getName(), cfg);  
    return cfg;  
}

最后整理解析的ActionConfig Map集合[DefaultConfiguration#packageContexts]  最终已Map<nameSpace,Map<actionName, ActionConfig>>形式存储

public void rebuildRuntimeConfiguration() {  
    runtimeConfiguration = buildRuntimeConfiguration();  
} 


protected synchronized RuntimeConfiguration buildRuntimeConfiguration() throws ConfigurationException {  
    Map<String, Map<String, ActionConfig>> namespaceActionConfigs = new LinkedHashMap<String, Map<String, ActionConfig>>();  
    Map<String, String> namespaceConfigs = new LinkedHashMap<String, String>();  
  
    for (PackageConfig packageConfig : packageContexts.values()) {  
  
        if (!packageConfig.isAbstract()) {  
            String namespace = packageConfig.getNamespace();  
            Map<String, ActionConfig> configs = namespaceActionConfigs.get(namespace);  
  
            if (configs == null) {  
                configs = new LinkedHashMap<String, ActionConfig>();  
            }  
  
            Map<String, ActionConfig> actionConfigs = packageConfig.getAllActionConfigs();  
  
            for (Object o : actionConfigs.keySet()) {  
                String actionName = (String) o;  
                ActionConfig baseConfig = actionConfigs.get(actionName);  
                //这里设置action的拦截器  
                //TODO buildFullActionConfig  
                configs.put(actionName, buildFullActionConfig(packageConfig, baseConfig));  
            }  
            //key -> nameSpace  
            //value - > <actionName, ActionConfig>  ,ActionConfig包含了拦截器  
            namespaceActionConfigs.put(namespace, configs);  
            if (packageConfig.getFullDefaultActionRef() != null) {  
                namespaceConfigs.put(namespace, packageConfig.getFullDefaultActionRef());  
            }  
        }  
    }  
    return new RuntimeConfigurationImpl(namespaceActionConfigs, namespaceConfigs);  
}  

解析完成后,  最终会保存到DefaultConfiguration  runtimeConfiguration变量中
初始化顺序图:


猜你喜欢

转载自kangrui.iteye.com/blog/2010666