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

首先我们去找一下在那里加载了配置文件,前面我们已经走过一遍加载配置文件的流程,现在我们就重点加载配置文件中的数据,首先我们去看一下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.isNeedsRefresh()) {
                            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;
    }

去寻找一个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上
到此参数注入原理完毕

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值