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. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章