這一篇文章主要是記錄struts.xml的初始化,還原struts2.xml的初始化流程。源碼依據struts2-2.3.16.3版本。
struts2初始化入口,位于web.xml中:
1 <filter> 2 <filter-name>struts2</filter-name> 3 <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 4 </filter>
外部中斷初始化的流程是什么? 調用StrutsPrepareAndExecuteFilterinit(FilterConfig filterConfig)方法,進行初始化:
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(filterConfig.getServletContext(), dispatcher);execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);postInit(dispatcher, filterConfig);} finally {if (dispatcher != null) {dispatcher.cleanUpAfterInit();}init.cleanup();}}
InitOperations定義了初始化的實現,提供struts2初始化的各個部件的構建過程,包括:logger、dispatcher、static content loader 。我們這里只關心dispatcher的初始化流程。
dispather的init過程被分解了多個步驟:
init_FileManager();init_DefaultProperties(); // [1]init_TraditionalXmlConfigurations(); // [2]//初始化struts.xmlinit_LegacyStrutsProperties(); // [3]init_CustomConfigurationProviders(); // [5]init_FilterInitParameters() ; // [6]init_AliasStandardObjects() ; // [7]
零配置初始化流程失敗。 其中第2個步驟:init_TraditionalXmlConfigurations();就是準備初始化xml文件的:
1 private void init_TraditionalXmlConfigurations() { 2 String configPaths = initParams.get("config"); 3 if (configPaths == null) { 4 configPaths = DEFAULT_CONFIGURATION_PATHS;//DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml",即默認需要初始化這三個配置文件。 5 } 6 String[] files = configPaths.split("\\s*[,]\\s*"); 7 for (String file : files) { 8 if (file.endsWith(".xml")) { 9 if ("xwork.xml".equals(file)) { 10 configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false)); 11 } else { 12 configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext)); 13 } 14 } else { 15 throw new IllegalArgumentException("Invalid configuration file name"); 16 } 17 } 18 }
默認根據struts-default.xml,struts-plugin.xml,struts.xml (可根據init-param:config 修改加載路徑) 分別創建三個 org.apache.struts2.config. StrutsXmlConfigurationProvider,其中方法register實現默認會從相應配置文件讀取props加載到setting 中,會將bean放入ContainerBuilder中,最后將三個containerProviders并加入containerProviders。
全部的providers準備好后,preLoad配置的時候就會把配置初始化出來:
1 Container container = init_PreloadConfiguration(); 2 3 4 private Container init_PreloadConfiguration() { 5 Configuration config = configurationManager.getConfiguration(); 6 Container container = config.getContainer(); 7 8 boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD)); 9 LocalizedTextUtil.setReloadBundles(reloadi18n); 10 11 ContainerHolder.store(container); 12 13 return container; 14 }
jvm源碼分析、 configurationManager.getConfiguration()的作用是根據配置將configuration對象實例化,并根據當前的container將內容填充:
1 public synchronized Configuration getConfiguration() { 2 if (configuration == null) { 3 setConfiguration(createConfiguration(defaultFrameworkBeanName)); 4 try { 5 configuration.reloadContainer(getContainerProviders()); 6 } catch (ConfigurationException e) { 7 setConfiguration(null); 8 throw new ConfigurationException("Unable to load configuration.", e); 9 } 10 } else { 11 conditionalReload(); 12 } 13 14 return configuration; 15 }
?
調用每個providers的register方法解析制定的xml,此處的providers即包含前面在init_TraditionalXmlConfigurations中初始化的struts-default.xml,struts-plugin.xml,struts.xml的三個providers。
1 public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException { 2 packageContexts.clear(); 3 loadedFileNames.clear(); 4 List<PackageProvider> packageProviders = new ArrayList<PackageProvider>(); 5 6 ContainerProperties props = new ContainerProperties(); 7 ContainerBuilder builder = new ContainerBuilder(); 8 Container bootstrap = createBootstrapContainer(providers); 9 for (final ContainerProvider containerProvider : providers) 10 { 11 bootstrap.inject(containerProvider); 12 containerProvider.init(this); 13 containerProvider.register(builder, props); 14 }
shell程序設計、 繼續向下看StrutsXmlConfigurationProvider.register方法,可以看到關鍵邏輯是在父類里面:
1 StrutsXmlConfigurationProvider.java 2 public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException { 3 if (servletContext != null && !containerBuilder.contains(ServletContext.class)) { 4 containerBuilder.factory(ServletContext.class, new Factory<ServletContext>() { 5 public ServletContext create(Context context) throws Exception { 6 return servletContext; 7 } 8 }); 9 } 10 super.register(containerBuilder, props); 11 }
這里將在xml文件中定義的bean、contants、unknown-handler-stack 元素取出來并加載到容器中去。
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 ("bean".equals(nodeName)) {} else if ("constant".equals(nodeName)) {} else if (nodeName.equals("unknown-handler-stack")) {}}} }
loadPackages負責初始化struts2 pacakge定義
1 for (Document doc : documents) { 2 Element rootElement = doc.getDocumentElement(); 3 NodeList children = rootElement.getChildNodes(); 4 int childSize = children.getLength(); 5 6 for (int i = 0; i < childSize; i++) { 7 Node childNode = children.item(i); 8 9 if (childNode instanceof Element) { 10 Element child = (Element) childNode; 11 12 final String nodeName = child.getNodeName(); 13 14 if ("package".equals(nodeName)) { 15 PackageConfig cfg = addPackage(child); 16 if (cfg.isNeedsRefresh()) { 17 reloads.add(child); 18 } 19 } 20 } 21 } 22 loadExtraConfiguration(doc); 23 }
請簡述Struts2開發環境的搭建步驟。?
?
?
?