Struts2.3.14分析-初始化2--Struts.xml解析
2015-05-06 21:14
316 查看
承接上一篇,在Filter初始化时,在DefautlConfiguration类中调用containerProvider的方法,完成对各个ContainerProvider的解析,我们着重分析对Struts.xml文件的读取和解析。
DefaultConfiguration类
XmlConfigurationProvider类
StrutsXmlConfigurationProvider类
ContainerBuilder类
这样,在调用完init和register方法后,将struts.xml内容转化为Java对象存储起来,方便后面管理。
DefaultConfiguration类
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException { packageContexts.clear(); loadedFileNames.clear(); List<PackageProvider> packageProviders = new ArrayList<PackageProvider>(); ContainerProperties props = new ContainerProperties(); ContainerBuilder builder = new ContainerBuilder(); for (final ContainerProvider containerProvider : providers) { containerProvider.init(this);① containerProvider.register(builder, props);② } …… // 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); } } …… return packageProviders; }
XmlConfigurationProvider类
private Set<String> loadedFileUrls = new HashSet<String>(); private Configuration configuration; private Set<String> includedFileNames; private List<Document> documents; //①init 方法,读取该Provider对应的xml文件,转换成documents public void init(Configuration configuration) { this.configuration = configuration; this.includedFileNames = configuration.getLoadedFileNames(); //加载xml文件 loadDocuments(configFileName); } private void loadDocuments(String configFileName) { try { loadedFileUrls.clear(); documents = loadConfigurationFiles(configFileName, null); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Error loading configuration file " + configFileName, e); } } # 将xml文件转换成document,并存放在list中 private List<Document> loadConfigurationFiles(String fileName, Element includeElement) { List<Document> docs = new ArrayList<Document>(); List<Document> finalDocs = new ArrayList<Document>(); 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 { if (LOG.isInfoEnabled()) { 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()); 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) { throw new ConfigurationException("Caught exception while loading file " + fileName, 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)); } }); # 解析文件,将xml文件转换成document对象 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(); # 处理include标签,xml文件嵌套 if ("include".equals(nodeName)) { String includeFileName = child.getAttribute("file"); if (includeFileName.indexOf('*') != -1) { // handleWildCardIncludes(includeFileName, docs, child); ClassPathFinder wildcardFinder = new ClassPathFinder(); wildcardFinder.setPattern(includeFileName); Vector<String> wildcardMatches = wildcardFinder.findMatches(); for (String match : wildcardMatches) { finalDocs.addAll(loadConfigurationFiles(match, child)); } } else { finalDocs.addAll(loadConfigurationFiles(includeFileName, child)); } } } } finalDocs.add(doc); loadedFileUrls.add(url.toString()); } if (LOG.isDebugEnabled()) { LOG.debug("Loaded action configuration from: " + fileName); } } return finalDocs; } protected Iterator<URL> getConfigurationUrls(String fileName) throws IOException { return ClassLoaderUtil.getResources(fileName, XmlConfigurationProvider.class, false); } //②register方法,处理xml文件的beans、constant标签 public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException { if (LOG.isInfoEnabled()) { LOG.info("Parsing configuration file [" + configFileName + "]"); } 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(); if ("bean".equals(nodeName)) { #将bean信息加载到containBuild中,struts自己的IoC 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 { if (containerBuilder.contains(ctype, name)) { 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); } containerBuilder.factory(ctype, name, new LocatableFactory(name, ctype, cimpl, scope, childNode), scope); } 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 { if (LOG.isDebugEnabled()) { LOG.debug("Unable to load optional class: #0", ex, impl); } } } } else if ("constant".equals(nodeName)) { # 将constant信息加载到LocatableProperties String name = child.getAttribute("name"); String value = child.getAttribute("value"); 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); } } } } } //③loadPackages方法加载Package节点信息 public void loadPackages() throws ConfigurationException { List<Element> reloads = new ArrayList<Element>(); //检查Package extends是否处在闭环,如A extends B,但B却 extends A verifyPackageStructure();⑴ 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)) { 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(); declaredPackages.clear(); configuration = null; } private void verifyPackageStructure() { DirectedGraph<String> graph = new DirectedGraph<String>(); 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)) { String packageName = child.getAttribute("name"); declaredPackages.put(packageName, child); graph.addNode(packageName); String extendsAttribute = child.getAttribute("extends"); List<String> parents = ConfigurationUtil.buildParentListFromString(extendsAttribute); //添加顶点和变到图中 for (String parent : parents) { graph.addNode(parent); graph.addEdge(packageName, parent); } } } } } CycleDetector<String> detector = new CycleDetector<String>(graph); //检测图中是否包含回路 if (detector.containsCycle()) { StringBuilder builder = new StringBuilder("The following packages participate in cycles:"); for (String packageName : detector.getVerticesInCycles()) { builder.append(" "); builder.append(packageName); } throw new ConfigurationException(builder.toString()); } } protected PackageConfig addPackage(Element packageElement) throws ConfigurationException { PackageConfig.Builder newPackage = buildPackageContext(packageElement); if (newPackage.isNeedsRefresh()) { return newPackage.build(); } if (LOG.isDebugEnabled()) { LOG.debug("Loaded " + newPackage); } // add result types (and default result) to this package addResultTypes(newPackage, packageElement); // load the interceptors and interceptor stacks for this package loadInterceptors(newPackage, packageElement); // load the default interceptor reference for this package loadDefaultInterceptorRef(newPackage, packageElement); // load the default class ref for this package loadDefaultClassRef(newPackage, packageElement); // load the global result list for this package loadGlobalResults(newPackage, packageElement); // load the global exception handler list for this package loadGobalExceptionMappings(newPackage, packageElement); // get actions NodeList actionList = packageElement.getElementsByTagName("action"); for (int i = 0; i < actionList.getLength(); i++) { Element actionElement = (Element) actionList.item(i); //处理Package中的Action addAction(actionElement, newPackage); } // load the default action reference for this package loadDefaultActionRef(newPackage, packageElement); PackageConfig cfg = newPackage.build(); //将Package信息加入DefaultConfiguration中 configuration.addPackageConfig(cfg.getName(), cfg); return cfg; } protected void addAction(Element actionElement, PackageConfig.Builder packageContext) throws ConfigurationException { String name = actionElement.getAttribute("name"); String className = actionElement.getAttribute("class"); String methodName = actionElement.getAttribute("method"); Location location = DomHelper.getLocationObject(actionElement); if (location == null) { if (LOG.isWarnEnabled()) { LOG.warn("location null for " + className); } } //methodName should be null if it's not set methodName = (methodName.trim().length() > 0) ? methodName.trim() : null; Map<String, ResultConfig> results; try { //处理Action下的多个result results = buildResults(actionElement, packageContext); } catch (ConfigurationException e) { throw new ConfigurationException("Error building results for action " + name + " in namespace " + packageContext.getNamespace(), e, actionElement); } List<InterceptorMapping> interceptorList = buildInterceptorList(actionElement, packageContext); List<ExceptionMappingConfig> exceptionMappings = buildExceptionMappings(actionElement, packageContext); Set<String> allowedMethods = buildAllowedMethods(actionElement, packageContext); ActionConfig actionConfig = new ActionConfig.Builder(packageContext.getName(), name, className) .methodName(methodName) .addResultConfigs(results) .addInterceptors(interceptorList) .addExceptionMappings(exceptionMappings) .addParams(XmlHelper.getParams(actionElement)) .addAllowedMethod(allowedMethods) .location(location) .build(); packageContext.addActionConfig(name, actionConfig); }
StrutsXmlConfigurationProvider类
public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException { if (servletContext != null && !containerBuilder.contains(ServletContext.class)) { containerBuilder.factory(ServletContext.class, new Factory<ServletContext>() { public ServletContext create(Context context) throws Exception { return servletContext; } }); } #调用XmlConfigurationProvider的register方法 super.register(containerBuilder, props); }
ContainerBuilder类
#容器类,保存配置文件的Beans public final class ContainerBuilder { final Map<Key<?>, InternalFactory<?>> factories = new HashMap<Key<?>, InternalFactory<?>>(); final List<InternalFactory<?>> singletonFactories = new ArrayList<InternalFactory<?>>(); final List<Class<?>> staticInjections = new ArrayList<Class<?>>(); boolean created; boolean allowDuplicates = false; public ContainerBuilder injectStatics(Class<?>... types) { staticInjections.addAll(Arrays.asList(types)); return this; } private void ensureNotCreated() { if (created) { throw new IllegalStateException("Container already created."); } } private void checkKey(Key<?> key) { if (factories.containsKey(key) && !allowDuplicates) { throw new DependencyException("Dependency mapping for " + key + " already exists."); } } public <T> ContainerBuilder factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope) { InternalFactory<? extends T> factory = new InternalFactory<T>(){ // This factory creates new instances of the given implementation. // We have to lazy load the constructor because the Container // hasn't been created yet. volatile ContainerImpl.ConstructorInjector<? extends T> constructor; @SuppressWarnings("unchecked") public T create(InternalContext context) { if (constructor == null) { this.constructor = context.getContainerImpl().getConstructor(implementation); } return (T) constructor.construct(context, type); } @Override public String toString() { return new LinkedHashMap<String, Object>() {{ put("type", type); put("name", name); put("implementation", implementation); put("scope", scope); }}.toString(); } }; return factory(Key.newInstance(type, name), factory, scope); } private <T> ContainerBuilder factory(final Key<T> key, InternalFactory<? extends T> factory, Scope scope) { ensureNotCreated(); checkKey(key); final InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory); factories.put(key, scopedFactory); if (scope == Scope.SINGLETON) { singletonFactories.add(new InternalFactory<T>() { public T create(InternalContext context) { try { context.setExternalContext(ExternalContext.newInstance( null, key, context.getContainerImpl())); return scopedFactory.create(context); } finally { context.setExternalContext(null); } } }); } return this; }
这样,在调用完init和register方法后,将struts.xml内容转化为Java对象存储起来,方便后面管理。
相关文章推荐
- Struts2.3.14分析-初始化1
- Struts2.3.14路由分析
- Struts1.3.x中的ActionServlet源码分析之初始化
- struts 初始化分析
- struts ModuleConfig类加载初始化的过程以及RequestProcessor类源码分析
- struts1源码分析(二)初始化主线
- struts1源码分析(二)初始化主线
- Docker Libnetwork Bridge插件实现代码分析----初始化部分
- 【Spring源码分析】非懒加载的单例Bean初始化过程(上篇)
- 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)
- 组策略提示管理单元初始化失败的分析解决
- Solr初始化源码分析-Solr初始化与启动
- 区域函数[置顶] linux 3.4.10 内核内存管理源代码分析5:伙伴系统初始化
- linux内存源码分析 - 页表的初始化
- 用Quickfix详解Fix(四)–核心类分析和初始化
- cc2530操作任务系统初始化分析
- linux IIC子系统分析(五)——I2C plaform device 初始化
- Struts1框架二之项目执行流程(源代码分析1)
- ZooKeeper服务端单机版 ZooKeeperServer初始化源码分析
- Linux内核--网络协议栈深入分析(四)--套接字内核初始化和创建过程