Struts2源码浅析-初始化

虚拟机器人平台CoppeliaSim(Vrep)的逆运动学教学 相信看这篇博客的人都知道CoppeliaSim是做什么的,因此这里不多赘述。CoppeliaSim从最早的Vrep到现在已经更新了N个版本,从过去Vrep3.x开始使用的我这里小小地吐槽一下这个软件。CoppeliaSim每一个版本都有更新,问题是这些更新有时候不能向前兼容,而且时不时更新地让人不知所措(对于有紧急任务的时候真的很火大啊)。 以本文所展示地逆运动学来说,CoppeliaSim在4.0.0之后又大变,推翻了过往所有的拖动模块链接之类的构建方式,转而采用直接通过代码来实现逆运动学。 简单版逆运动 阅读详情

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 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变量中

初始化顺序图:

 

地平线RDKX3初始配置与USB无线网卡 地平线X3无线网卡配置 阅读详情

相关推荐

点餐系统数据库设计--SQL Server

友情链接 1、学生成绩管理系统数据库设计–MySQL 学生成绩管理系统数据库设计–MySQL 2、医疗信息管理系统数据库–MySQL 医疗信息管理系统数据库–MySQL 3、邮件管理数据库设计–MySQL 邮件管理数据库设计–MySQL 4、SQL Server医疗信息管理系统数据库【英文版-源码】–(Medical Management System Database) SQL Server医疗信息管理系统数据库【英文版-源码】–(Medical Management System Database) 5

若如初见 8万+

Vcpkg不只是Windows的玩具:在WSL2 Ubuntu里搭建C++跨平台开发环境全记录

本文详细介绍了如何在WSL2 Ubuntu环境中使用Vcpkg搭建C++跨平台开发环境。通过Vcpkg的跨平台包管理功能,开发者可以轻松管理依赖库,实现Windows和Linux双平台的统一开发体验。文章涵盖了环境准备、依赖管理、CMake集成以及持续集成实践,帮助团队提升协作效率。

weixin_30266885的博客 470

无人机蜂群联合指挥作战技术详解

随着人工智能、通信技术、新材料等领域的不断进步,无人机蜂群联合指挥作战技术将迎来更加广阔的发展前景。未来,无人机蜂群将更加智能化、自主化,能够执行更加复杂、精细的作战任务。同时,加强国际合作,共同制定国际规则和标准,将是推动无人机蜂群技术健康发展的重要方向。无人机蜂群技术,是指通过先进的通信技术、自主导航与决策算法,将大量小型、低成本、功能各异的无人机组织成一个高度协同的群体,执行复杂多样的军事任务。2. 通信与数据链:采用高速、低延迟、抗干扰的通信技术,保障群体内无人机间的信息交换。

专注多旋翼、复合翼无人机技术研究,从事低空经济行业。 1546

Struts2源码阅读(四)_Dispatcher&ConfigurationProvider续

接下来第三步:init_LegacyStrutsProperties()调用的是调用的是LegacyPropertiesConfigurationProvider通过比较前面DefaultPropertiesProvider与调用的是LegacyPropertiesConfigurationProvider.发现DefaultPropertiesProvider继承自后者,但重写了register...

i'm thinking... 163

S32K3xx系列DMA驱动实战:EB配置与Mcal接口应用全解析(含Adc硬件触发示例)

本文深入解析S32K3xx系列MCU的DMA驱动开发,涵盖EB工具配置与Mcal接口应用,特别包含ADC硬件触发示例。通过详细架构分析、实战配置步骤和工业级应用案例,帮助开发者掌握AUTOSAR环境下DMA高效数据传输技术,提升汽车电子和工业控制系统的性能。

weixin_29162439的博客 463

DeepSeek跨会话协作指南:让AI成为你的「第二大脑」

通过DeepSeek的跨会话协作系统,用户实测工作效率提升63%。

紫夜若涵的博客 1475

Struts2源码分析

Struts2架构图        请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和Dispatcher;FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。        ActionMapper取得了ActionMapping后,在Dispa

lick4050312的专栏 3649

片上眼图(Eye-opening monitor)

当它们值不同的时候error counter +1,通过统计RX到的码元个数、error counter,可以获得offset sampler上下左右不停的调整位置时的一个误码率(BER),通过这个误码率去描绘出眼图。如上图所示,eye-scan RX端 offset sampler独立且并行的和使用CDR sample的采样电路一起跑,offset-sampler可以任意调整水平(time)和垂直(voltage)方向的偏移(如下图所示),在一个UI内产生一个全新的sample点。

沈土豪的书屋 4416

struts2+spring配置后bean加载,bean为什么会初始化2次

下面是我的服务器出错情况: 15:53:02,546 INFO [XmlWebApplicationContext] Bean factory for application conte xt [org.springframework.web.context.support.XmlWebApplicationContext@18c56d]: or g.springframework.b...

lipeihua 249

QGis软件 —— 1、Windows10下载安装QGis及插件

QGis —— 1、Windows10下载安装QGis及插件

5159

手把手教你学simulink(16.10)-- 基于Simulink的IIR滤波器(Infinite Impulse Response Filter)项目

基于Simulink的IIR滤波器(Infinite Impulse Response Filter)项目的详细实例介绍。这个项目将重点放在IIR滤波器的设计、实现和仿真上,帮助你理解和应用IIR滤波器在信号处理中的作用。

MHD0815的博客 706

com.opensymphony.xwork2.config.ConfigurationManager.addConfigurationProvider

下午 org.apache.catalina.core.StandardContext filterStart 严重: Exception starting filter Struts2 java.lang.NoSuchMethodError: com.opensymphony.xwork2.config.ConfigurationManager.addConfigurationPr...

weixin_34342992的博客 349

手把手教你学Simulink--基于高频与高速信号处理的滤波器场景实例:毫米波雷达中匹配滤波器的多目标分辨仿真

在自动驾驶、智能交通和工业感知等领域,毫米波雷达(mmWave Radar)因其高分辨率全天候工作和抗电磁干扰能力,成为关键的感知传感器。其核心信号处理算法之一是匹配滤波器(Matched Filter),用于在强噪声背景下最大化信噪比(SNR),实现对微弱目标的检测。在调频连续波(FMCW, Frequency-Modulated Continuous Wave)雷达中,发射信号为线性调频(Chirp)信号。当信号遇到多个目标时,回波是多个延迟版本的叠加。

MHD0815的博客 134

Struts2源码浅析-初始化(转载)

本文参考自:http://blog.youkuaiyun.com/java2000_wl/article/details/7572828 如果有侵犯您知识产权的地方,烦请通知本人,本人将即刻停止侵权行为 --------begin 在web.xml中配置的StrutsPrepareAndExecuteFilter类是struts2的入口类,它实现了Filter接口 ,它的init 方法为初始化入...

weixin_30835933的博客 192

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Struts2源码浅析-ConfigurationProvider

ConfigurationProvider接口 主要完成struts配置文件 加载 注册过程 ConfigurationProvider接口定义 public interface ConfigurationProvider extends ContainerProvider, PackageProvider { } ContainerProvider接口定义 /** * 容器加载 注册

天行健,君子以自强不息 4513

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Struts2源码粗略分析二:初始化详解

分析初始化部分,阅读时最好一边读一边debug,这样理解更清楚更深刻!

KNIGHTRCOM(rcom10002的专栏) 2632

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Struts2.3.15.1源码浅析

Struts2 两大运行主线: 1.初始化主线:初始化主线主要是为Struts2创建运行环境(此处的环境与Struts2身处的Web环境是有区别的),初始化入口StrutsPrepareAndExecuteFilter继承 Filter,遵循Filter规范,初始化只是在应用启动的时候运行一次,以后无论过来多少HttpServletRequest都不会再运行啦。 StrutsPrepar...

Sonicery_D 206

struts2_源码学习_init()

续struts2_源码学习_目录 作为一个过滤器类,请求到达的第一步就是进行初始化,即init()操作。 StrutsPrepareAndExecuteFilter.init public void init(FilterConfig filterConfig) throws ServletException { //初始化InitOperations ...

Onion的博客 332

struts2源码浅析(三)

接上篇http://mazhiyuan.iteye.com/blog/1202086,本文着重dispatcher和filter的探讨。   Dispatcher已经在之前讲过,FilterDispatcher是Struts2的核心控制器,首先看一下init()方法。 public void init(FilterConfig filterConfig) throws ServletExce...

坐看流年 184

struts2源码之struts.xml的初始化

这一篇文章主要是记录struts.xml的初始化。将其中的一些用户所填的信息封装到相应的类中 当用户在客户端向服务器发送一条请求。web.xml的拦截器类就会拦截,跳转到这个拦截器类中。如果是第一次操作那么init()方法就会被执行,从这个方法的名字我们就可以知道它主要是完成一些初始化的工作。 public void init(FilterConfig filterConfig) throws

追本溯源的专栏 2490

浅析struts2源码中对requset的封装

   当前台发送来HttpServletRequest的请求的时候,struts2是用StrutsPrepareAndExecuteFilter的doFilter来接收并处理的. (现在web.xml的配置都是StrutsPrepareAndExecuteFilter了吧) 而struts2刚开始就对request和response进行了封装   prepare.setEncodingA...

jcloud159的博客 193

Struts源码学习 — 初始化ModuleConfig

Struts版本——1.2.9 Digester版本——1.6     初始化ModuleConfig就是指Struts将struts-config.xml初始化为ModuleConfig对象,实现这个动作的代码在ActionServlet的init()方法中,如下: initModuleConfigFactory(); // Initialize ...

gemini18的专栏 960
上一篇: Spring 整合 Hessian
下一篇: Struts2源码浅析-Container
胸口碎大石_
博客等级 码龄17年 1154粉丝 82原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值