struts2的配置文件的参数注入原理
2016-09-26 12:08
477 查看
首先我们去找一下在那里加载了配置文件,前面我们已经走过一遍加载配置文件的流程,现在我们就重点加载配置文件中的数据,首先我们去看一下Struts2的过滤器的init方法中这一行代码, init.initStaticContentLoader(config, dispatcher);
直接到getContainer方法
下一步
下一步reloadContainer()方法
到 provider.loadPackages()这里
到 addPackage(child);
这里就加载配置文件信息到PackageConfig 中
先来看一下configuration.getPackageConfig(packageName);
可以发现这里是从packageContexts中获取,接下来的packageConfig应该跟packageContexts有关,也就是说我现在解析获取的packageConfig最后会被防盗packageContexts中。
下面我们继续,这里我们以result集为例进行讲解。
addResultTypes(newPackage, packageElement);
这里就将resultTypeConfig加载到packageContext中,而在这个packageContext是传递进来的,也就是addPackage方法中newPackage对象,而addPackage返回的newPackage.build(),也就是cfg。
下面将是如何取到这个packageConfig?
这里我们先到DefaultConfiguration类中,发现有一个有一个内部类RuntimeConfigurationImpl,我们去找一下是那一段代码创建了RuntimeConfigurationImpl
这一段代码创建了一个RuntimeConfigurationImpl对象,这里是遍历packageContexts,然后我namespaceConfigs,namespaceActionConfigs进行添加数据,然后利用这两个创建RuntimeConfigurationImpl。
下面我们开始去讲调用result的时候,当action执行完毕时,执行result,上源码
在DefaultActionInvocation的invoke方法中调用executeResult()这个方法
查看createResult();这个方法
看看proxy.getConfig()方法
去寻找一
ba5c
个config什么时候被赋值,在创建了proxy后执行了prepare()而在这里就是为config赋值了,前面我们提到那个内部类,getRuntimeConfiguration()就是获取到内部的实例对象
protected void prepare() {
String profileKey = “create DefaultActionProxy: “;
try {
UtilTimerStack.push(profileKey);
config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName);
那么来看一下啊getActionConfig方法
看这个findActionConfigInNamespace方法
就是在namespaceActionConfigs,namespaceConfigs对象中获取config,而namespaceActionConfigs,namespaceConfigs在这个内部类实例化时就有了,而且这两个是跟packageContext有关,而配置文件信心load后是放入packageContext中的。
所以这里返回的config应该是配置文件中的信息。
那么回过来看createResult方法,里面 return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
去看看呗
resultConfig.getParams()获取到注入的参数,然后设置到result上
到此参数注入原理完毕
public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) { StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class); loader.setHostConfig(filterConfig); return loader; }
直接到getContainer方法
public Container getContainer() { ConfigurationManager mgr = getConfigurationManager(); if (mgr == null) { throw new IllegalStateException("The configuration manager shouldn't be null"); } else { Configuration config = mgr.getConfiguration(); if (config == null) { throw new IllegalStateException("Unable to load configuration"); } else { return config.getContainer(); } } }
下一步
public synchronized Configuration getConfiguration() { if (configuration == null) { setConfiguration(createConfiguration(defaultFrameworkBeanName)); try { configuration.reloadContainer(getContainerProviders()); } catch (ConfigurationException e) { setConfiguration(null); throw new ConfigurationException("Unable to load configuration.", e); } } else { conditionalReload(); } return configuration; }
下一步reloadContainer()方法
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException { packageContexts.clear(); loadedFileNames.clear(); List<PackageProvider> packageProviders = new ArrayList<>(); ContainerProperties props = new ContainerProperties(); ContainerBuilder builder = new ContainerBuilder(); Container bootstrap = createBootstrapContainer(providers); for (final ContainerProvider containerProvider : providers) { bootstrap.inject(containerProvider); containerProvider.init(this); containerProvider.register(builder, props); } 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 { // Set the bootstrap container for the purposes of factory creation 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) { container.inject(containerProvider); ((PackageProvider)containerProvider).loadPackages(); packageProviders.add((PackageProvider)containerProvider); } } // Then process any package providers from the plugins Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class); for (String name : packageProviderNames) { PackageProvider provider = container.getInstance(PackageProvider.class, name); provider.init(this); provider.loadPackages(); packageProviders.add(provider); } rebuildRuntimeConfiguration(); } finally { if (oldContext == null) { ActionContext.setContext(null); } } return packageProviders; }
到 provider.loadPackages()这里
public void loadPackages() throws ConfigurationException { List<Element> reloads = new ArrayList<Element>(); 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.isNeedsRefres 4000 h()) { reloads.add(child); } } } } loadExtraConfiguration(doc); } if (reloads.size() > 0) { reloadRequiredPackages(reloads); } for (Document doc : documents) { loadExtraConfiguration(doc); } documents.clear(); declaredPackages.clear(); configuration = null; }
到 addPackage(child);
protected PackageConfig addPackage(Element packageElement) throws ConfigurationException { String packageName = packageElement.getAttribute("name"); PackageConfig packageConfig = configuration.getPackageConfig(packageName); if (packageConfig != null) { LOG.debug("Package [{}] already loaded, skipping re-loading it and using existing PackageConfig [{}]", packageName, packageConfig); return packageConfig; } PackageConfig.Builder newPackage = buildPackageContext(packageElement); if (newPackage.isNeedsRefresh()) { return newPackage.build(); } 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); loadGlobalAllowedMethods(newPackage, packageElement); // load the global exception handler list for this package loadGlobalExceptionMappings(newPackage, packageElement); // get actions NodeList actionList = packageElement.getElementsByTagName("action"); for (int i = 0; i < actionList.getLength(); i++) { Element actionElement = (Element) actionList.item(i); addAction(actionElement, newPackage); } // load the default action reference for this package loadDefaultActionRef(newPackage, packageElement); PackageConfig cfg = newPackage.build(); configuration.addPackageConfig(cfg.getName(), cfg); return cfg; }
这里就加载配置文件信息到PackageConfig 中
先来看一下configuration.getPackageConfig(packageName);
public PackageConfig getPackageConfig(String name) { return packageContexts.get(name); }
可以发现这里是从packageContexts中获取,接下来的packageConfig应该跟packageContexts有关,也就是说我现在解析获取的packageConfig最后会被防盗packageContexts中。
下面我们继续,这里我们以result集为例进行讲解。
addResultTypes(newPackage, packageElement);
protected void addResultTypes(PackageConfig.Builder packageContext, Element element) { NodeList resultTypeList = element.getElementsByTagName("result-type"); for (int i = 0; i < resultTypeList.getLength(); i++) { Element resultTypeElement = (Element) resultTypeList.item(i); String name = resultTypeElement.getAttribute("name"); String className = resultTypeElement.getAttribute("class"); String def = resultTypeElement.getAttribute("default"); Location loc = DomHelper.getLocationObject(resultTypeElement); Class clazz = verifyResultType(className, loc); if (clazz != null) { String paramName = null; try { paramName = (String) clazz.getField("DEFAULT_PARAM").get(null); } catch (Throwable t) { LOG.debug("The result type [{}] doesn't have a default param [DEFAULT_PARAM] defined!", className, t); } ResultTypeConfig.Builder resultType = new ResultTypeConfig.Builder(name, className).defaultResultParam(paramName) .location(DomHelper.getLocationObject(resultTypeElement)); Map<String, String> params = XmlHelper.getParams(resultTypeElement); if (!params.isEmpty()) { resultType.addParams(params); } packageContext.addResultTypeConfig(resultType.build()); // set the default result type if (BooleanUtils.toBoolean(def)) { packageContext.defaultResultType(name); } } } }
这里就将resultTypeConfig加载到packageContext中,而在这个packageContext是传递进来的,也就是addPackage方法中newPackage对象,而addPackage返回的newPackage.build(),也就是cfg。
下面将是如何取到这个packageConfig?
这里我们先到DefaultConfiguration类中,发现有一个有一个内部类RuntimeConfigurationImpl,我们去找一下是那一段代码创建了RuntimeConfigurationImpl
protected synchronized RuntimeConfiguration buildRuntimeConfiguration() throws ConfigurationException { Map<String, Map<String, ActionConfig>> namespaceActionConfigs = new LinkedHashMap<>(); Map<String, String> namespaceConfigs = new LinkedHashMap<>(); 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<>(); } Map<String, ActionConfig> actionConfigs = packageConfig.getAllActionConfigs(); for (Object o : actionConfigs.keySet()) { String actionName = (String) o; ActionConfig baseConfig = actionConfigs.get(actionName); configs.put(actionName, buildFullActionConfig(packageConfig, baseConfig)); } namespaceActionConfigs.put(namespace, configs); if (packageConfig.getFullDefaultActionRef() != null) { namespaceConfigs.put(namespace, packageConfig.getFullDefaultActionRef()); } } } PatternMatcher<int[]> matcher = container.getInstance(PatternMatcher.class); return new RuntimeConfigurationImpl(Collections.unmodifiableMap(namespaceActionConfigs), Collections.unmodifiableMap(namespaceConfigs), matcher); }
这一段代码创建了一个RuntimeConfigurationImpl对象,这里是遍历packageContexts,然后我namespaceConfigs,namespaceActionConfigs进行添加数据,然后利用这两个创建RuntimeConfigurationImpl。
下面我们开始去讲调用result的时候,当action执行完毕时,执行result,上源码
if (proxy.getExecuteResult()) { executeResult(); }
在DefaultActionInvocation的invoke方法中调用executeResult()这个方法
private void executeResult() throws Exception { result = createResult(); String timerKey = "executeResult: " + getResultCode(); try { UtilTimerStack.push(timerKey); if (result != null) { result.execute(this); } else if (resultCode != null && !Action.NONE.equals(resultCode)) { throw new ConfigurationException("No result defined for action " + getAction().getClass().getName() + " and result " + getResultCode(), proxy.getConfig()); } else { if (LOG.isDebugEnabled()) { LOG.debug("No result returned for action {} at {}", getAction().getClass().getName(), proxy.getConfig().getLocation()); } } } finally { UtilTimerStack.pop(timerKey); } }
查看createResult();这个方法
public Result createResult() throws Exception { LOG.trace("Creating result related to resultCode [{}]", resultCode); if (explicitResult != null) { Result ret = explicitResult; explicitResult = null; return ret; } ActionConfig config = proxy.getConfig(); Map<String, ResultConfig> results = config.getResults(); ResultConfig resultConfig = null; try { resultConfig = results.get(resultCode); } catch (NullPointerException e) { LOG.debug("Got NPE trying to read result configuration for resultCode [{}]", resultCode); } if (resultConfig == null) { // If no result is found for the given resultCode, try to get a wildcard '*' match. resultConfig = results.get("*"); } if (resultConfig != null) { try { return objectFactory.buildResult(resultConfig, invocationContext.getContextMap()); } catch (Exception e) { LOG.error("There was an exception while instantiating the result of type {}", resultConfig.getClassName(), e); throw new XWorkException(e, resultConfig); } } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) { return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode); } return null; }
看看proxy.getConfig()方法
public ActionConfig getConfig() { return config; }
去寻找一
ba5c
个config什么时候被赋值,在创建了proxy后执行了prepare()而在这里就是为config赋值了,前面我们提到那个内部类,getRuntimeConfiguration()就是获取到内部的实例对象
protected void prepare() {
String profileKey = “create DefaultActionProxy: “;
try {
UtilTimerStack.push(profileKey);
config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName);
if (config == null && unknownHandlerManager.hasUnknownHandlers()) { config = unknownHandlerManager.handleUnknownAction(namespace, actionName); } if (config == null) { throw new ConfigurationException(getErrorMessage()); } resolveMethod(); if (config.isAllowedMethod(method)) { invocation.init(this); } else { throw new ConfigurationException(prepareNotAllowedErrorMessage()); } } finally { UtilTimerStack.pop(profileKey); } }
那么来看一下啊getActionConfig方法
public ActionConfig getActionConfig(String namespace, String name) { ActionConfig config = findActionConfigInNamespace(namespace, name); // try wildcarded namespaces if (config == null) { NamespaceMatch match = namespaceMatcher.match(namespace); if (match != null) { config = findActionConfigInNamespace(match.getPattern(), name); // If config found, place all the matches found in the namespace processing in the action's parameters if (config != null) { config = new ActionConfig.Builder(config) .addParams(match.getVariables()) .build(); } } } // fail over to empty namespace if (config == null && StringUtils.isNotBlank(namespace)) { config = findActionConfigInNamespace("", name); } return config; }
看这个findActionConfigInNamespace方法
private ActionConfig findActionConfigInNamespace(String namespace, String name) { ActionConfig config = null; if (namespace == null) { namespace = ""; } Map<String, ActionConfig> actions = namespaceActionConfigs.get(namespace); if (actions != null) { config = actions.get(name); // Check wildcards if (config == null) { config = namespaceActionConfigMatchers.get(namespace).match(name); // fail over to default action if (config == null) { String defaultActionRef = namespaceConfigs.get(namespace); if (defaultActionRef != null) { config = actions.get(defaultActionRef); } } } } return config; }
就是在namespaceActionConfigs,namespaceConfigs对象中获取config,而namespaceActionConfigs,namespaceConfigs在这个内部类实例化时就有了,而且这两个是跟packageContext有关,而配置文件信心load后是放入packageContext中的。
所以这里返回的config应该是配置文件中的信息。
那么回过来看createResult方法,里面 return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
去看看呗
public Result buildResult(ResultConfig resultConfig, Map<String, Object> extraContext) throws Exception { String resultClassName = resultConfig.getClassName(); Result result = null; if (resultClassName != null) { result = (Result) buildBean(resultClassName, extraContext); Map<String, String> params = resultConfig.getParams(); if (params != null) { for (Map.Entry<String, String> paramEntry : params.entrySet()) { try { reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), result, extraContext, true); } catch (ReflectionException ex) { if (result instanceof ReflectionExceptionHandler) { ((ReflectionExceptionHandler) result).handle(ex); } } } } } return result; }
resultConfig.getParams()获取到注入的参数,然后设置到result上
到此参数注入原理完毕
相关文章推荐
- Struts2 配置文件传递参数
- struts2配置文件中url传递参数中文乱码处理
- Struts2中,action配置文件中两个action带参数的调用
- Struts2配置文件及filer运行原理探析
- Spring placeHolder读取文件内容注入参数配置
- spring整合struts2后,struts2的action中调用服务层时,不需要在spring配置文件中去注入
- struts2 配置文件 重定向 redirect (带参数) 的写法
- struts2配置文件中参数的传递
- struts2 xml配置文件配置传参数
- 方法中注入配置文件中的参数注入不进来
- struts2配置文件中动态参数
- Struts2配置文件中传递参数的一个小问题
- Struts2配置文件中redirect传递中文参数乱码的解决办法!
- Spring中的注入注解Resource/Autowired以及配置文件中default-autowire参数详解
- struts2配置文件中参数的传递
- struts2配置文件中参数的传递
- struts2配置文件配置action时结果集传多个参数
- Struts2的配置文件中配置result时传中文参数的问题
- Properties 配置文件参数 注入bean中
- 修改Struts2的struts.xml配置文件位置和名称-重点是init-param参数用来切换加载的路径