您的位置:首页 > 编程语言 > Java开发

struts2的配置文件的参数注入原理

2016-09-26 12:08 477 查看
首先我们去找一下在那里加载了配置文件,前面我们已经走过一遍加载配置文件的流程,现在我们就重点加载配置文件中的数据,首先我们去看一下Struts2的过滤器的init方法中这一行代码, init.initStaticContentLoader(config, dispatcher);

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上

到此参数注入原理完毕
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  struts 参数 注入