Struts2的配置文件读取(一)

Struts2的配置文件读取(一)

struts2利用FilterDispatcher来拦截请求,然后进行请求的分发,在FilterDispatcher的#init()方法里,实现了配置文件的读入。

代码如下:

Java代码 复制代码
  1. public void init(FilterConfig filterConfig) throws ServletException {   
  2.     this.filterConfig = filterConfig;   
  3.        
  4.     dispatcher = createDispatcher(filterConfig);   
  5.     dispatcher.init();   
  6.        
  7.     String param = filterConfig.getInitParameter("packages");   
  8.     String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";   
  9.     if (param != null) {   
  10.         packages = param + " " + packages;   
  11.     }   
  12.     this.pathPrefixes = parse(packages);   
  13. }  
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        
        dispatcher = createDispatcher(filterConfig);
        dispatcher.init();
        
        String param = filterConfig.getInitParameter("packages");
        String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";
        if (param != null) {
            packages = param + " " + packages;
        }
        this.pathPrefixes = parse(packages);
    }


-------------------------------------------------------------------------------------------------

先调用#createDispatcher()来创建一个Dispatcher对象,并将FilterConfig中的属性读出,代码如下:

Java代码 复制代码
  1. protected Dispatcher createDispatcher(FilterConfig filterConfig) {   
  2.     Map params = new HashMap();   
  3.     for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {   
  4.         String name = (String) e.nextElement();   
  5.         String value = filterConfig.getInitParameter(name);   
  6.         params.put(name, value);   
  7.     }   
  8.     return new Dispatcher(filterConfig.getServletContext(), params);   
  9. }  
    protected Dispatcher createDispatcher(FilterConfig filterConfig) {
        Map params = new HashMap();
        for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
            String name = (String) e.nextElement();
            String value = filterConfig.getInitParameter(name);
            params.put(name, value);
        }
        return new Dispatcher(filterConfig.getServletContext(), params);
    }


在#createDispatcher()中,将Filter的配置中的所有属性都写入一个HashMap并作为参数传递给Dispatcher的构造函数。

-------------------------------------------------------------------------------------------------

再回到#init()函数中,创建完Dispatcher对象后,紧接着调用Dispatcher的#init()方法。代码如下:

Java代码 复制代码
  1. public void init() {   
  2.   
  3.     if (configurationManager == null) {   
  4.         configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);   
  5.     }   
  6.   
  7.     init_DefaultProperties(); // [1]   
  8.     init_TraditionalXmlConfigurations(); // [2]   
  9.     init_LegacyStrutsProperties(); // [3]   
  10.     init_ZeroConfiguration(); // [4]   
  11.     init_CustomConfigurationProviders(); // [5]   
  12.     init_MethodConfigurationProvider();   
  13.     init_FilterInitParameters(); // [6]   
  14.     init_AliasStandardObjects(); // [7]   
  15.   
  16.     Container container = init_PreloadConfiguration();   
  17.     init_CheckConfigurationReloading(container);   
  18.     init_CheckWebLogicWorkaround(container);   
  19.   
  20. }  
    public void init() {

        if (configurationManager == null) {
            configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
        }

        init_DefaultProperties(); // [1]
        init_TraditionalXmlConfigurations(); // [2]
        init_LegacyStrutsProperties(); // [3]
        init_ZeroConfiguration(); // [4]
        init_CustomConfigurationProviders(); // [5]
        init_MethodConfigurationProvider();
        init_FilterInitParameters(); // [6]
        init_AliasStandardObjects(); // [7]

        Container container = init_PreloadConfiguration();
        init_CheckConfigurationReloading(container);
        init_CheckWebLogicWorkaround(container);

    }


首先实例化一个ConfigurationManager对象。

然后就是调用一系列的#init_*()方法了。

-------------------------------------------------------------------------------------------------

●第一个是

Java代码 复制代码
  1. private void init_DefaultProperties() {   
  2.     configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());   
  3. }  
    private void init_DefaultProperties() {
        configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
    }


这个方法中是将一个DefaultPropertiesProvider对象追加到ConfigurationManager对象内部的ConfigurationProvider队列中。
DefaultPropertiesProvider的#register()方法可以载入org/apache/struts2/default.properties中定义的属性。

-------------------------------------------------------------------------------------------------

●第二个是

Java代码 复制代码
  1. private void init_TraditionalXmlConfigurations() {   
  2.     String configPaths = initParams.get("config");   
  3.     if (configPaths == null) {   
  4.         configPaths = DEFAULT_CONFIGURATION_PATHS;   
  5.     }   
  6.     String[] files = configPaths.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");   
  7.     for (String file : files) {   
  8.         if (file.endsWith(".xml")) {   
  9.             if ("xwork.xml".equals(file)) {   
  10.                 configurationManager.addConfigurationProvider(new XmlConfigurationProvider(   
  11.                         file, false));   
  12.             } else {   
  13.                 configurationManager   
  14.                         .addConfigurationProvider(new StrutsXmlConfigurationProvider(file,   
  15.                                 false, servletContext));   
  16.             }   
  17.         } else {   
  18.             throw new IllegalArgumentException("Invalid configuration file name");   
  19.         }   
  20.     }   
  21. }  
    private void init_TraditionalXmlConfigurations() {
        String configPaths = initParams.get("config");
        if (configPaths == null) {
            configPaths = DEFAULT_CONFIGURATION_PATHS;
        }
        String[] files = configPaths.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
        for (String file : files) {
            if (file.endsWith(".xml")) {
                if ("xwork.xml".equals(file)) {
                    configurationManager.addConfigurationProvider(new XmlConfigurationProvider(
                            file, false));
                } else {
                    configurationManager
                            .addConfigurationProvider(new StrutsXmlConfigurationProvider(file,
                                    false, servletContext));
                }
            } else {
                throw new IllegalArgumentException("Invalid configuration file name");
            }
        }
    }


这里负责载入的是FilterDispatcher的配置中所定义的config属性。
如果用户没有定义config属性,struts默认会载入DEFAULT_CONFIGURATION_PATHS这个值所代表的xml文件。
它的值为"struts-default.xml,struts-plugin.xml,struts.xml"。也就是说框架默认会载入这三个项目xml文件。

下一步框架会逐个判断每个config属性中定义的文件。如果文件名为"xwork.xml",框架会用XmlConfigurationProvider类去处理,反之则用StrutsXmlConfigurationProvider类去处理。

-------------------------------------------------------------------------------------------------

●第三个是

Java代码 复制代码
  1. private void init_LegacyStrutsProperties() {   
  2.     configurationManager.addConfigurationProvider(new LegacyPropertiesConfigurationProvider());   
  3. }  
    private void init_LegacyStrutsProperties() {
        configurationManager.addConfigurationProvider(new LegacyPropertiesConfigurationProvider());
    }


向ConfigurationManager加入了一个LegacyPropertiesConfigurationProvider。

-------------------------------------------------------------------------------------------------

●第四个是

Java代码 复制代码
  1. private void init_ZeroConfiguration() {   
  2.     String packages = initParams.get("actionPackages");   
  3.     if (packages != null) {   
  4.         String[] names = packages.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");   
  5.         // Initialize the classloader scanner with the configured packages   
  6.         if (names.length > 0) {   
  7.             ClasspathConfigurationProvider provider = new ClasspathConfigurationProvider(names);   
  8.             provider.setPageLocator(new ServletContextPageLocator(servletContext));   
  9.             configurationManager.addConfigurationProvider(provider);   
  10.         }   
  11.     }   
  12. }  
    private void init_ZeroConfiguration() {
        String packages = initParams.get("actionPackages");
        if (packages != null) {
            String[] names = packages.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
            // Initialize the classloader scanner with the configured packages
            if (names.length > 0) {
                ClasspathConfigurationProvider provider = new ClasspathConfigurationProvider(names);
                provider.setPageLocator(new ServletContextPageLocator(servletContext));
                configurationManager.addConfigurationProvider(provider);
            }
        }
    }


这次处理的是FilterDispatcher的配置中所定义的actionPackages属性。传说中的Struts 2 零配置。
该参数的值是一个以英文逗号(,)隔开的字符串,每个字符串都是一个包空间,Struts 2框架将扫描这些包空间下的Action类。

-------------------------------------------------------------------------------------------------

●第五个是

Java代码 复制代码
  1. private void init_CustomConfigurationProviders() {   
  2.     String configProvs = initParams.get("configProviders");   
  3.     if (configProvs != null) {   
  4.         String[] classes = configProvs.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");   
  5.         for (String cname : classes) {   
  6.             try {   
  7.                 Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());   
  8.                 ConfigurationProvider prov = (ConfigurationProvider) cls.newInstance();   
  9.                 configurationManager.addConfigurationProvider(prov);   
  10.             } catch (InstantiationException e) {   
  11.                 throw new ConfigurationException("Unable to instantiate provider: " + cname, e);   
  12.             } catch (IllegalAccessException e) {   
  13.                 throw new ConfigurationException("Unable to access provider: " + cname, e);   
  14.             } catch (ClassNotFoundException e) {   
  15.                 throw new ConfigurationException("Unable to locate provider class: " + cname, e);   
  16.             }   
  17.         }   
  18.     }   
  19. }  
    private void init_CustomConfigurationProviders() {
        String configProvs = initParams.get("configProviders");
        if (configProvs != null) {
            String[] classes = configProvs.split("[url=file:s*[,]//s]//s*[,]//s[/url]*");
            for (String cname : classes) {
                try {
                    Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());
                    ConfigurationProvider prov = (ConfigurationProvider) cls.newInstance();
                    configurationManager.addConfigurationProvider(prov);
                } catch (InstantiationException e) {
                    throw new ConfigurationException("Unable to instantiate provider: " + cname, e);
                } catch (IllegalAccessException e) {
                    throw new ConfigurationException("Unable to access provider: " + cname, e);
                } catch (ClassNotFoundException e) {
                    throw new ConfigurationException("Unable to locate provider class: " + cname, e);
                }
            }
        }
    }


此方法处理的是FilterDispatcher的配置中所定义的configProviders属性。负责载入用户自定义的ConfigurationProvider。

-------------------------------------------------------------------------------------------------

●第六个是

Java代码 复制代码
  1. private void init_FilterInitParameters() {   
  2.     configurationManager.addConfigurationProvider(new ConfigurationProvider() {   
  3.         public void destroy() {   
  4.         }   
  5.   
  6.         public void init(Configuration configuration) throws ConfigurationException {   
  7.         }   
  8.   
  9.         public void loadPackages() throws ConfigurationException {   
  10.         }   
  11.   
  12.         public boolean needsReload() {   
  13.             return false;   
  14.         }   
  15.   
  16.         public void register(ContainerBuilder builder, LocatableProperties props)   
  17.                 throws ConfigurationException {   
  18.             props.putAll(initParams);   
  19.         }   
  20.     });   
  21. }  
    private void init_FilterInitParameters() {
        configurationManager.addConfigurationProvider(new ConfigurationProvider() {
            public void destroy() {
            }

            public void init(Configuration configuration) throws ConfigurationException {
            }

            public void loadPackages() throws ConfigurationException {
            }

            public boolean needsReload() {
                return false;
            }

            public void register(ContainerBuilder builder, LocatableProperties props)
                    throws ConfigurationException {
                props.putAll(initParams);
            }
        });
    }


此方法用来处理FilterDispatcher的配置中所定义的所有属性。

-------------------------------------------------------------------------------------------------

●第七个是

Java代码 复制代码
  1. private void init_AliasStandardObjects() {   
  2.     configurationManager.addConfigurationProvider(new BeanSelectionProvider());   
  3. }  
	private void init_AliasStandardObjects() {
		configurationManager.addConfigurationProvider(new BeanSelectionProvider());
	}


-------------------------------------------------------------------------------------------------

执行完七个init_*方法后,Dispatcher的#init()会接着调用#init_PreloadConfiguration(),构建一个用于依赖注射的Container对象。

Java代码 复制代码
  1. private Container init_PreloadConfiguration() {   
  2.     Configuration config = configurationManager.getConfiguration();   
  3.     Container container = config.getContainer();   
  4.   
  5.     boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class,   
  6.             StrutsConstants.STRUTS_I18N_RELOAD));   
  7.     LocalizedTextUtil.setReloadBundles(reloadi18n);   
  8.   
  9.     ObjectTypeDeterminer objectTypeDeterminer = container   
  10.             .getInstance(ObjectTypeDeterminer.class);   
  11.     ObjectTypeDeterminerFactory.setInstance(objectTypeDeterminer);   
  12.   
  13.     return container;   
  14. }  
    private Container init_PreloadConfiguration() {
        Configuration config = configurationManager.getConfiguration();
        Container container = config.getContainer();

        boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class,
                StrutsConstants.STRUTS_I18N_RELOAD));
        LocalizedTextUtil.setReloadBundles(reloadi18n);

        ObjectTypeDeterminer objectTypeDeterminer = container
                .getInstance(ObjectTypeDeterminer.class);
        ObjectTypeDeterminerFactory.setInstance(objectTypeDeterminer);

        return container;
    }


此方法首先获取到ConfigurationManager中的Configuration对象,在#getConfiguration()内部,调用上边6步添加到ConfigurationManager的ConfigurationProviders的#register()方法。

Java代码 复制代码
  1. public synchronized Configuration getConfiguration() {   
  2.     if (configuration == null) {   
  3.         setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));   
  4.         try {   
  5.           configuration.reload(getConfigurationProviders());   
  6.         } catch (ConfigurationException e) {   
  7.           setConfiguration(null);   
  8.           throw e;   
  9.         }   
  10.     } else {   
  11.         conditionalReload();   
  12.     }   
  13.   
  14.     return configuration;   
  15. }  
    public synchronized Configuration getConfiguration() {
        if (configuration == null) {
            setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));
            try {
              configuration.reload(getConfigurationProviders());
            } catch (ConfigurationException e) {
              setConfiguration(null);
              throw e;
            }
        } else {
            conditionalReload();
        }

        return configuration;
    }


其中的重点就是DefaultConfiguration的#reload()方法。

Java代码 复制代码
  1. public synchronized void reload(List providers) throws ConfigurationException {   
  2.     packageContexts.clear();   
  3.     loadedFileNames.clear();   
  4.   
  5.     ContainerProperties props = new ContainerProperties();   
  6.     ContainerBuilder builder = new ContainerBuilder();   
  7.     for (ConfigurationProvider configurationProvider : providers)   
  8.     {   
  9.         configurationProvider.init(this);   
  10.         configurationProvider.register(builder, props);   
  11.     }   
  12.     props.setConstants(builder);   
  13.        
  14.     builder.factory(Configuration.classnew Factory() {   
  15.         public Configuration create(Context context) throws Exception {   
  16.           return DefaultConfiguration.this;   
  17.         }   
  18.     });   
  19.        
  20.     try {   
  21.         // Set the object factory for the purposes of factory creation   
  22.         ObjectFactory.setObjectFactory(new ObjectFactory());   
  23.            
  24.         container = builder.create(false);   
  25.         objectFactory = container.getInstance(ObjectFactory.class);   
  26.         ObjectFactory.setObjectFactory(objectFactory);   
  27.            
  28.         for (ConfigurationProvider configurationProvider : providers)   
  29.         {   
  30.           container.inject(configurationProvider);   
  31.           configurationProvider.loadPackages();   
  32.         }   
  33.   
  34.         rebuildRuntimeConfiguration();   
  35.     } finally {   
  36.         ObjectFactory.setObjectFactory(null);   
  37.     }   
  38. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值