struts2_源碼學習_Dispatcher(1)

Logging System

目錄

Dispatcher

第一步:創建ConfigurationManager。

第二步:往ConfigurationManager添加一個FileManagerProvider

第三步:往ConfigurationManager添加一個DefaultPropertiesProvider

第四步:往ConfigurationManager添加一個StrutsXmlConfigurationProvider

第五步:往ConfigurationManager添加一個PropertiesConfigurationProvider

第六步:往ConfigurationManager添加用戶自定義的xmlprovider

第七步:往ConfigurationManager添加一個ConfigurationProvider實現類用於解析Filter參數

第八步:往ConfigurationManager添加一個BeanSelectionProvider

第九步:創建container


Dispatcher

接下來的語句就是:(初始化分配器)

dispatcher = init.initDispatcher(config);

我們進行源碼跟蹤到:

org.apache.struts2.dispatcher.InitOperation

    public Dispatcher initDispatcher(HostConfig filterConfig) {
        //創建
        Dispatcher dispatcher = this.createDispatcher(filterConfig);
        //初始化
        dispatcher.init();
        return dispatcher;
    }


....

    protected Dispatcher createDispatcher(HostConfig filterConfig) {
        Map<String, String> params = new HashMap();
        //遍歷filterConfig把init-param全部拿出來,就是那些在web.xml配置在Filter標籤裏面的初始化參數
        Iterator e = filterConfig.getInitParameterNames();
        
        while(e.hasNext()) {
            String name = (String)e.next();
            String value = filterConfig.getInitParameter(name);
            params.put(name, value);
        }
        //創建
        return new Dispatcher(filterConfig.getServletContext(), params);
    }

接下來看下一條語句:

dispatcher.init();
    public void init() {
        if (this.configurationManager == null) {
            //配置文件管理器
            this.configurationManager = this.createConfigurationManager("default");
        }

        try {
            //文件管理器
            this.init_FileManager();
            init_DefaultProperties(); //加入默認配置供給器,解析org/apache/struts2/default.properties
            init_TraditionalXmlConfigurations(); // struts-default.xml 
            init_LegacyStrutsProperties(); // struts-default.xml,struts-plugin.xml,struts.xml
            init_CustomConfigurationProviders(); // struts.properties
            init_FilterInitParameters() ; // default.properties
            init_AliasStandardObjects() ; // struts.custom.properties
            Container container = this.init_PreloadConfiguration();
            container.inject(this);
            this.init_CheckWebLogicWorkaround(container);
            if (!dispatcherListeners.isEmpty()) {
                Iterator i$ = dispatcherListeners.iterator();

                while(i$.hasNext()) {
                    DispatcherListener l = (DispatcherListener)i$.next();
                    l.dispatcherInitialized(this);
                }
            }

            this.errorHandler.init(this.servletContext);
        } catch (Exception var4) {
            LOG.error("Dispatcher initialization failed", var4);
            throw new StrutsException(var4);
        }
    }

第一步:創建ConfigurationManager。


/**

 * ConfigurationManager - central for XWork Configuration management, including its ConfigurationProvider.

*/

public class ConfigurationManager {

    protected Configuration configuration;

    private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<ContainerProvider>();

    private List<PackageProvider> packageProviders = new CopyOnWriteArrayList<PackageProvider>();

    public ConfigurationManager() 

    public ConfigurationManager(String name)

    public synchronized Configuration getConfiguration() 

    protected Configuration createConfiguration(String beanName) 

    public synchronized void setConfiguration(Configuration configuration)

    public List<ContainerProvider> getContainerProviders() 

    public void setContainerProviders(List<ContainerProvider> containerProviders) 

    public void addContainerProvider(ContainerProvider provider) 

    public void clearContainerProviders()

    private void clearContainerProvider(ContainerProvider containerProvider)

    public synchronized void destroyConfiguration()

    public synchronized void conditionalReload()

    private void updateReloadConfigsFlag()

    private boolean needReloadPackageProviders() 

    private boolean needReloadContainerProviders(List<ContainerProvider> providers)

    private void reloadProviders(List<ContainerProvider> providers)

    public synchronized void reload()

}


從源碼中我們可以看到三個屬性:

configuration(Configuration):存儲配置信息;

containerProviders(List<ContainerProvider>):對應的 ContainerProvider 用來加載<constants>和<bean>兩種元素以及default.properties,struts.properties文件中聲明的常量(保存在Key和InternalFactory類中,最終保存在factories中,然後將容器元素從文件中加載後對象化了也就是生成了Container類)。之所以說它是容器元素,是因爲它們配置的信息最終反映到Container對象中,也就是容器了。

packageProviders(List<PackageProvider>):PackageProvider 用來加載我們經常配置的<package>元素(保存在PackageConfig這個類中)。

那麼ConfigurationManager這個類的功能便是明顯了:維護一個Configuration對象,管理配置信息。

接下來我們來看看Configuration、PackageProvider和ContainerProvider這三個類:

package com.opensymphony.xwork2.config;

public interface Configuration extends Serializable {
    void rebuildRuntimeConfiguration();

    PackageConfig getPackageConfig(String var1);

    Set<String> getPackageConfigNames();

    Map<String, PackageConfig> getPackageConfigs();

    RuntimeConfiguration getRuntimeConfiguration();

    void addPackageConfig(String var1, PackageConfig var2);

    PackageConfig removePackageConfig(String var1);

    void destroy();

    List<PackageProvider> reloadContainer(List<ContainerProvider> var1) throws ConfigurationException;

    Container getContainer();

    Set<String> getLoadedFileNames();

    List<UnknownHandlerConfig> getUnknownHandlerStack();

    void setUnknownHandlerStack(List<UnknownHandlerConfig> var1);
}

該接口只是定義了行爲,數據的存儲還需要數據結構,這就在實現類了。我們來看一下它的實現類DefaultConfiguration :

public class DefaultConfiguration implements Configuration {

    protected Map<String, PackageConfig> packageContexts = new LinkedHashMap<String, PackageConfig>(); 

    protected RuntimeConfiguration runtimeConfiguration;

    protected Container container;

    protected String defaultFrameworkBeanName;

    protected Set<String> loadedFileNames = new TreeSet<String>();

    protected List<UnknownHandlerConfig> unknownHandlerStack;

    ObjectFactory objectFactory;

}

其中還有個RuntimeConfiguration屬性,它封裝了運行時的Action配置等信息。

下面是兩個Provider以及他們整合成的同一接口ConfigurationProvider的源代碼:

package com.opensymphony.xwork2.config;

public interface PackageProvider {
    void init(Configuration var1) throws ConfigurationException;

    boolean needsReload();

    void loadPackages() throws ConfigurationException;
}
package com.opensymphony.xwork2.config;

import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.util.location.LocatableProperties;

public interface ContainerProvider {
    void destroy();

    void init(Configuration var1) throws ConfigurationException;

    boolean needsReload();

    void register(ContainerBuilder var1, LocatableProperties var2) throws ConfigurationException;
}
package com.opensymphony.xwork2.config;

public interface ConfigurationProvider extends ContainerProvider, PackageProvider {
}

我們可以重點關注的兩個方法:

loadPackages():加載配置信息;

register(ContainerBuilder var1, LocatableProperties var2):將<bean>和<constant>信息加載到Container中。(這裏可以涉及到的參數ContainerBuilder,從字面意義上我們已經可以知道了這是一個構建器(構建者模式)。也就是Container最終是通過ContainerBuilder構造出來的。)

到這裏我們可以大概整理一下struts是如何加載配置文件的:

由×××Provider將配置文件加載到PackageConfig、Key等實體類中,然後加載(loadPackages())到Configuration進行保存, 其中對於<bean>這樣的配置信息會被註冊(register(...))到ContainerBuilder的類中,再由ContainerBuilder構造出Container。最後由ConfigurationManager來維護這些配置信息。

第二步:往ConfigurationManager添加一個FileManagerProvider

this.init_FileManager();
    private void init_FileManager() throws ClassNotFoundException {
        String fileManagerFactoryClassName;
        Class fileManagerFactoryClass;
        if (this.initParams.containsKey("struts.fileManager")) {//初始化參數中是否由“struts.fileManager”,一般沒有
            fileManagerFactoryClassName = (String)this.initParams.get("struts.fileManager");
            fileManagerFactoryClass = Class.forName(fileManagerFactoryClassName);
            LOG.info("Custom FileManager specified: {}", fileManagerFactoryClassName);
            this.configurationManager.addContainerProvider(new FileManagerProvider(fileManagerFactoryClass, fileManagerFactoryClass.getSimpleName()));
        } else {
            this.configurationManager.addContainerProvider(new FileManagerProvider(JBossFileManager.class, "jboss"));
        }

        if (this.initParams.containsKey("struts.fileManagerFactory")) {//初始化參數中是否由“struts.fileManagerFactory”,一般沒有
            fileManagerFactoryClassName = (String)this.initParams.get("struts.fileManagerFactory");
            fileManagerFactoryClass = Class.forName(fileManagerFactoryClassName);
            LOG.info("Custom FileManagerFactory specified: {}", fileManagerFactoryClassName);
            this.configurationManager.addContainerProvider(new FileManagerFactoryProvider(fileManagerFactoryClass));
        }

    }

程序執行:

            this.configurationManager.addContainerProvider(new FileManagerProvider(JBossFileManager.class, "jboss"));

這一條分支語句,也就是一個FileManagerProvider對象被加入到了List中。我們看看FileManagerProvider:

package com.opensymphony.xwork2.config;

public class FileManagerProvider implements ContainerProvider {
    private Class<? extends FileManager> fileManagerClass;
    private String name;

    public FileManagerProvider(Class<? extends FileManager> fileManagerClass, String name) {
        this.fileManagerClass = fileManagerClass;
        this.name = name;
    }

    public void destroy() {
    }

    public void init(Configuration configuration) throws ConfigurationException {
    }

    public boolean needsReload() {
        return false;
    }

    public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
        builder.factory(FileManager.class, this.name, this.fileManagerClass, Scope.SINGLETON);
    }
}

實現了ContainerProvider接口,看register()的實現,它調用了參數ContainerBuiler的factory()方法,就是向ContainerBuilder注入參數的,創建一個FileManager對象。關於FileManager類:

package com.opensymphony.xwork2;

public interface FileManager {
    void setReloadingConfigs(boolean var1);

    boolean fileNeedsReloading(String var1);

    boolean fileNeedsReloading(URL var1);

    InputStream loadFile(URL var1);

    void monitorFile(URL var1);

    URL normalizeToFileProtocol(URL var1);

    boolean support();

    boolean internal();

    Collection<? extends URL> getAllPhysicalUrls(URL var1) throws IOException;
}

看接口開頭的註釋,可以知道這個類的功能就是訪問文件系統中的文件並且監控文件是否被修改了。如果被修改了,可能就要重新載入了。那麼之前factory()方法會創建出什麼類呢?也就是參數傳遞進去的JBossFileManager類了。

總結一下,就是init_FileManager的功能就是往configurationManager的List<ContainerProvider>屬性添加一個元素FileManagerProvider。接下來的工作都類似了。所有添加Provider的工作都是爲了最終創建出一個可用的Container(到時創建Container時,會一一調用這些provider的register()),以及對象化的事件映射配置元素。

第三步:往ConfigurationManager添加一個DefaultPropertiesProvider

            this.init_DefaultProperties();
package org.apache.struts2.config;

public class DefaultPropertiesProvider extends PropertiesConfigurationProvider {
    public DefaultPropertiesProvider() {
    }

    public void destroy() {
    }

    public void init(Configuration configuration) throws ConfigurationException {
    }

    public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
        try {
            PropertiesSettings defaultSettings = new PropertiesSettings("org/apache/struts2/default");
            this.loadSettings(props, defaultSettings);
        } catch (Exception var4) {
            throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", var4);
        }
    }
}
package org.apache.struts2.config;

public class PropertiesConfigurationProvider implements ConfigurationProvider {

...

    protected void loadSettings(LocatableProperties props, Settings settings) {
        Iterator i = settings.list();

        while(i.hasNext()) {
            String name = (String)i.next();
            props.setProperty(name, settings.get(name), settings.getLocation(name));
        }

    }
}

從名字上來看我們就可以推測出這一步的作用就是加載properties文件。我們可以看看PropertiesSetting這個實體類:

package org.apache.struts2.config;

class PropertiesSettings implements Settings {
    private static final Logger LOG = LogManager.getLogger(PropertiesSettings.class);
    private LocatableProperties settings;

    public PropertiesSettings(String name) {
        URL settingsUrl = ClassLoaderUtil.getResource(name + ".properties", this.getClass());
        if (settingsUrl == null) {
            LOG.debug("{}.properties missing", name);
            this.settings = new LocatableProperties();
        } else {
            this.settings = new LocatableProperties(new LocationImpl((String)null, settingsUrl.toString()));

            try {
                InputStream in = settingsUrl.openStream();
                Throwable var4 = null;

                try {
                    this.settings.load(in);
                } catch (Throwable var14) {
                    var4 = var14;
                    throw var14;
                } finally {
                    if (in != null) {
                        if (var4 != null) {
                            try {
                                in.close();
                            } catch (Throwable var13) {
                                var4.addSuppressed(var13);
                            }
                        } else {
                            in.close();
                        }
                    }

                }

            } catch (IOException var16) {
                throw new StrutsException("Could not load " + name + ".properties: " + var16, var16);
            }
        }
    }

    ...

}

具體的我們就不說了,從下面兩句代碼應該可以大概推測是加載org/apche/struts2/default.properties。

PropertiesSettings defaultSettings = new PropertiesSettings("org/apache/struts2/default");

URL settingsUrl = ClassLoaderUtil.getResource(name + ".properties", this.getClass());

第四步:往ConfigurationManager添加一個StrutsXmlConfigurationProvider

            this.init_TraditionalXmlConfigurations();
    private void init_TraditionalXmlConfigurations() {
        String configPaths = (String)this.initParams.get("config");
        if (configPaths == null) {
            configPaths = "struts-default.xml,struts-plugin.xml,struts.xml";
        }

        String[] files = configPaths.split("\\s*[,]\\s*");
        String[] arr$ = files;
        int len$ = files.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            String file = arr$[i$];
            if (!file.endsWith(".xml")) {
                throw new IllegalArgumentException("Invalid configuration file name");
            }

            this.configurationManager.addContainerProvider(this.createStrutsXmlConfigurationProvider(file, false, this.servletContext));
        }

    }

容易看出加載的文件是:struts-default.xml,struts-plugin.xml,struts.xml 這樣的.xml文件。

我們看一下它所繼承的父類:XmlConfigurationProvider的register方法

package com.opensymphony.xwork2.config.providers;
 
public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
        LOG.trace("Parsing configuration file [{}]", this.configFileName);
        Map<String, Node> loadedBeans = new HashMap();
        Iterator i$ = this.documents.iterator();

        while(i$.hasNext()) {
            Document doc = (Document)i$.next();
            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;
                    String nodeName = child.getNodeName();
                    String type;
                    String name;
                    if ("bean".equals(nodeName)) {//加載<bean>結點信息
                        type = child.getAttribute("type");
                        name = child.getAttribute("name");
                        String impl = child.getAttribute("class");
                        String onlyStatic = child.getAttribute("static");
                        String scopeStr = child.getAttribute("scope");
                        boolean optional = "true".equals(child.getAttribute("optional"));
                        Scope scope = Scope.SINGLETON;//Scope爲枚舉類型,作用域
                        if ("prototype".equals(scopeStr)) {
                            scope = Scope.PROTOTYPE;
                        } else if ("request".equals(scopeStr)) {
                            scope = Scope.REQUEST;
                        } else if ("session".equals(scopeStr)) {
                            scope = Scope.SESSION;
                        } else if ("singleton".equals(scopeStr)) {
                            scope = Scope.SINGLETON;
                        } else if ("thread".equals(scopeStr)) {
                            scope = Scope.THREAD;
                        }

                        if (StringUtils.isEmpty(name)) {//<bean>的name屬性爲空則初始化爲default
                            name = "default";
                        }

                        try {
                            Class classImpl = ClassLoaderUtil.loadClass(impl, this.getClass());
                            Class classType = classImpl;
                            if (StringUtils.isNotEmpty(type)) {
                                classType = ClassLoaderUtil.loadClass(type, this.getClass());
                            }

                            if ("true".equals(onlyStatic)) {
                                classImpl.getDeclaredClasses();
                                containerBuilder.injectStatics(new Class[]{classImpl});
                            } else {
                                if (containerBuilder.contains(classType, name)) {
                                    Location loc = LocationUtils.getLocation(loadedBeans.get(classType.getName() + name));
                                    if (this.throwExceptionOnDuplicateBeans) {
                                        throw new ConfigurationException("Bean type " + classType + " with the name " + name + " has already been loaded by " + loc, child);
                                    }
                                }

                                classImpl.getDeclaredConstructors();
                                LOG.debug("Loaded type: {} name: {} impl: {}", type, name, impl);
                                containerBuilder.factory(classType, name, new LocatableFactory(name, classType, classImpl, scope, childNode), scope);
                            }

                            loadedBeans.put(classType.getName() + name, child);
                        } catch (Throwable var23) {
                            if (!optional) {
                                throw new ConfigurationException("Unable to load bean: type:" + type + " class:" + impl, var23, childNode);
                            }

                            LOG.debug("Unable to load optional class: {}", impl);
                        }
                    } else if ("constant".equals(nodeName)) {//加載<constant>結點
                        type = child.getAttribute("name");
                        name = child.getAttribute("value");
                        if (this.valueSubstitutor != null) {
                            LOG.debug("Substituting value [{}] using [{}]", name, this.valueSubstitutor.getClass().getName());
                            name = this.valueSubstitutor.substitute(name);
                        }
                        //常量信息存放在Properties類中
                        props.setProperty(type, name, childNode);
                    } else if (nodeName.equals("unknown-handler-stack")) {
                        List<UnknownHandlerConfig> unknownHandlerStack = new ArrayList();
                        NodeList unknownHandlers = child.getElementsByTagName("unknown-handler-ref");
                        int unknownHandlersSize = unknownHandlers.getLength();

                        for(int k = 0; k < unknownHandlersSize; ++k) {
                            Element unknownHandler = (Element)unknownHandlers.item(k);
                            Location location = LocationUtils.getLocation(unknownHandler);
                            unknownHandlerStack.add(new UnknownHandlerConfig(unknownHandler.getAttribute("name"), location));
                        }

                        if (!unknownHandlerStack.isEmpty()) {
                            this.configuration.setUnknownHandlerStack(unknownHandlerStack);
                        }
                    }
                }
            }
        }

    }

 可以看到加載的是<bean> <constant> <unknow-handler-stack>這一結點的信息,其中<constant>保存的是常量信息,封裝在Properties類中(繼承了HashTable)。

接着看loadPackage這個方法:

public void loadPackages() throws ConfigurationException {
        List<Element> reloads = new ArrayList();
        this.verifyPackageStructure();
        Iterator i$ = this.documents.iterator();

        Document doc;
        while(i$.hasNext()) {
            doc = (Document)i$.next();
            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;
                    String nodeName = child.getNodeName();
                    if ("package".equals(nodeName)) {//加載<package>結點
                        PackageConfig cfg = this.addPackage(child);
                        if (cfg.isNeedsRefresh()) {
                            reloads.add(child);
                        }
                    }
                }
            }

            this.loadExtraConfiguration(doc);
        }

        if (reloads.size() > 0) {
            //這個方法涉及到了extend屬性,嘗試找到parent package
            this.reloadRequiredPackages(reloads);
        }

        i$ = this.documents.iterator();

        while(i$.hasNext()) {
            doc = (Document)i$.next();
            this.loadExtraConfiguration(doc);
        }

        this.documents.clear();
        this.declaredPackages.clear();
        this.configuration = null;
    }

最關鍵的已經代碼當然就是   if ("package".equals(nodeName))  了,很明顯就是加載<package>結點信息了。封裝在PackageConfig,有興趣可以自己看看,裏面會一些明顯的屬性名稱如:Action、Result等。

第五步:往ConfigurationManager添加一個PropertiesConfigurationProvider

            this.init_LegacyStrutsProperties();

該方法添加的是PropertiesConfigurationProvider。 

package org.apache.struts2.config;


public class PropertiesConfigurationProvider implements ConfigurationProvider {


    public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
        DefaultSettings settings = new DefaultSettings();
        this.loadSettings(props, settings);
    }

    protected void loadSettings(LocatableProperties props, Settings settings) {
        Iterator i = settings.list();

        while(i.hasNext()) {
            String name = (String)i.next();
            props.setProperty(name, settings.get(name), settings.getLocation(name));
        }

    }
}

可以看到register方法中,有一個DefaultSetting的類,我們看看這個類中加載的應該是什麼信息。

package org.apache.struts2.config;

public class DefaultSettings implements Settings {
    private static final Logger LOG = LogManager.getLogger(DefaultSettings.class);
    private Settings delegate;

    public DefaultSettings() {
        ArrayList list = new ArrayList();

        try {
            list.add(new PropertiesSettings("struts"));
        } catch (Exception var7) {
            LOG.warn("DefaultSettings: Could not find or error in struts.properties", var7);
        }

        this.delegate = new DelegatingSettings(list);
        String files = this.delegate.get("struts.custom.properties");
        if (files != null) {
            StringTokenizer customProperties = new StringTokenizer(files, ",");

            while(customProperties.hasMoreTokens()) {
                String name = customProperties.nextToken();

                try {
                    list.add(new PropertiesSettings(name));
                } catch (Exception var6) {
                    LOG.error("DefaultSettings: Could not find {}.properties. Skipping.", name);
                }
            }

            this.delegate = new DelegatingSettings(list);
        }

    }

    public Location getLocation(String name) {
        return this.delegate.getLocation(name);
    }

    public String get(String aName) throws IllegalArgumentException {
        return this.delegate.get(aName);
    }

    public Iterator list() {
        return this.delegate.list();
    }
}

仍然用到了PropertiesSetting,那麼應該就是struts.properties這個文件了。我們就不細看下去了。

第六步:往ConfigurationManager添加用戶自定義的xmlprovider

private void init_CustomConfigurationProviders() {
        //這裏應該是找到自定義xmlProviders的配置信息
        String configProvs = (String)this.initParams.get("configProviders");
        if (configProvs != null) {
            String[] classes = configProvs.split("\\s*[,]\\s*");
            String[] arr$ = classes;
            int len$ = classes.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                String cname = arr$[i$];

                try {
                    //加載×××Provider類
                    Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
                    ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
                    if (prov instanceof ServletContextAwareConfigurationProvider) {
                        ((ServletContextAwareConfigurationProvider)prov).initWithContext(this.servletContext);
                    }
                    //加入到configurationManager中
                    this.configurationManager.addContainerProvider(prov);
                } catch (InstantiationException var9) {
                    throw new ConfigurationException("Unable to instantiate provider: " + cname, var9);
                } catch (IllegalAccessException var10) {
                    throw new ConfigurationException("Unable to access provider: " + cname, var10);
                } catch (ClassNotFoundException var11) {
                    throw new ConfigurationException("Unable to locate provider class: " + cname, var11);
                }
            }
        }

    }

主要是作爲struus2框架提供給用戶的擴展點。

第七步:往ConfigurationManager添加一個ConfigurationProvider實現類用於解析Filter參數

    private void init_FilterInitParameters() {
        this.configurationManager.addContainerProvider(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 {
                //可以注意一下這裏已經不是builder.register了。可以推測一下LocatableProperties是什麼作用。
                props.putAll(Dispatcher.this.initParams);
            }
        });
    }

用了一個匿名內部類,將filter參數放入容器中,被容器保管。這樣,在action中也可以很方便的訪問filter參數。

第八步:往ConfigurationManager添加一個BeanSelectionProvider

    private void init_AliasStandardObjects() {
        this.configurationManager.addContainerProvider(new DefaultBeanSelectionProvider());
    }

接下來的這部分學習筆記,是筆者自己猜測的,不保證正確性。 

package org.apache.struts2.config;

public class DefaultBeanSelectionProvider extends AbstractBeanSelectionProvider {
    private static final Logger LOG = LogManager.getLogger(DefaultBeanSelectionProvider.class);

    public DefaultBeanSelectionProvider() {
    }

    public void register(ContainerBuilder builder, LocatableProperties props) {
        this.alias(ObjectFactory.class, "struts.objectFactory", builder, props);
        this.alias(ActionFactory.class, "struts.objectFactory.actionFactory", builder, props);
        this.alias(ResultFactory.class, "struts.objectFactory.resultFactory", builder, props);
        this.alias(ConverterFactory.class, "struts.objectFactory.converterFactory", builder, props);
        this.alias(InterceptorFactory.class, "struts.objectFactory.interceptorFactory", builder, props);
        this.alias(ValidatorFactory.class, "struts.objectFactory.validatorFactory", builder, props);
        this.alias(UnknownHandlerFactory.class, "struts.objectFactory.unknownHandlerFactory", builder, props);
        this.alias(FileManagerFactory.class, "struts.fileManagerFactory", builder, props, Scope.SINGLETON);
        this.alias(XWorkConverter.class, "struts.xworkConverter", builder, props);
        this.alias(CollectionConverter.class, "struts.converter.collection", builder, props);
        this.alias(ArrayConverter.class, "struts.converter.array", builder, props);
        this.alias(DateConverter.class, "struts.converter.date", builder, props);
        this.alias(NumberConverter.class, "struts.converter.number", builder, props);
        this.alias(StringConverter.class, "struts.converter.string", builder, props);
        this.alias(ConversionPropertiesProcessor.class, "struts.converter.properties.processor", builder, props);
        this.alias(ConversionFileProcessor.class, "struts.converter.file.processor", builder, props);
        this.alias(ConversionAnnotationProcessor.class, "struts.converter.annotation.processor", builder, props);
        this.alias(TypeConverterCreator.class, "struts.converter.creator", builder, props);
        this.alias(TypeConverterHolder.class, "struts..converter.holder", builder, props);
        this.alias(TextProvider.class, "struts.xworkTextProvider", builder, props, Scope.PROTOTYPE);
        this.alias(TextProvider.class, "struts.textProvider", builder, props, Scope.PROTOTYPE);
        this.alias(TextProviderFactory.class, "struts.textProviderFactory", builder, props, Scope.PROTOTYPE);
        this.alias(LocaleProviderFactory.class, "struts.localeProviderFactory", builder, props);
        this.alias(LocalizedTextProvider.class, "struts.localizedTextProvider", builder, props);
        this.alias(ActionProxyFactory.class, "struts.actionProxyFactory", builder, props);
        this.alias(ObjectTypeDeterminer.class, "struts.objectTypeDeterminer", builder, props);
        this.alias(ActionMapper.class, "struts.mapper.class", builder, props);
        this.alias(MultiPartRequest.class, "struts.multipart.parser", builder, props, Scope.PROTOTYPE);
        this.alias(FreemarkerManager.class, "struts.freemarker.manager.classname", builder, props);
        this.alias(VelocityManager.class, "struts.velocity.manager.classname", builder, props);
        this.alias(UrlRenderer.class, "struts.urlRenderer", builder, props);
        this.alias(ActionValidatorManager.class, "struts.actionValidatorManager", builder, props);
        this.alias(ValueStackFactory.class, "struts.valueStackFactory", builder, props);
        this.alias(ReflectionProvider.class, "struts.reflectionProvider", builder, props);
        this.alias(ReflectionContextFactory.class, "struts.reflectionContextFactory", builder, props);
        this.alias(PatternMatcher.class, "struts.patternMatcher", builder, props);
        this.alias(ContentTypeMatcher.class, "struts.contentTypeMatcher", builder, props);
        this.alias(StaticContentLoader.class, "struts.staticContentLoader", builder, props);
        this.alias(UnknownHandlerManager.class, "struts.unknownHandlerManager", builder, props);
        this.alias(UrlHelper.class, "struts.view.urlHelper", builder, props);
        this.alias(TextParser.class, "struts.expression.parser", builder, props);
        this.alias(DispatcherErrorHandler.class, "struts.dispatcher.errorHandler", builder, props);
        this.alias(ExcludedPatternsChecker.class, "struts.excludedPatterns.checker", builder, props, Scope.PROTOTYPE);
        this.alias(AcceptedPatternsChecker.class, "struts.acceptedPatterns.checker", builder, props, Scope.PROTOTYPE);
        this.switchDevMode(props);
        this.convertIfExist(props, "struts.ognl.logMissingProperties", "logMissingProperties");
        this.convertIfExist(props, "struts.ognl.enableExpressionCache", "enableOGNLExpressionCache");
        this.convertIfExist(props, "struts.ognl.enableOGNLEvalExpression", "enableOGNLEvalExpression");
        this.convertIfExist(props, "struts.ognl.allowStaticMethodAccess", "allowStaticMethodAccess");
        this.convertIfExist(props, "struts.configuration.xml.reload", "reloadXmlConfiguration");
        this.convertIfExist(props, "struts.excludedClasses", "ognlExcludedClasses");
        this.convertIfExist(props, "struts.excludedPackageNamePatterns", "ognlExcludedPackageNamePatterns");
        this.convertIfExist(props, "struts.excludedPackageNames", "ognlExcludedPackageNames");
        this.convertIfExist(props, "struts.additional.excludedPatterns", "additionalExcludedPatterns");
        this.convertIfExist(props, "struts.additional.acceptedPatterns", "additionalAcceptedPatterns");
        this.convertIfExist(props, "struts.override.excludedPatterns", "overrideExcludedPatterns");
        this.convertIfExist(props, "struts.override.acceptedPatterns", "overrideAcceptedPatterns");
    }

    private void switchDevMode(LocatableProperties props) {
        if ("true".equalsIgnoreCase(props.getProperty("struts.devMode"))) {
            if (props.getProperty("struts.i18n.reload") == null) {
                props.setProperty("struts.i18n.reload", "true");
            }

            if (props.getProperty("struts.configuration.xml.reload") == null) {
                props.setProperty("struts.configuration.xml.reload", "true");
            }

            if (props.getProperty("struts.freemarker.templatesCache.updateDelay") == null) {
                props.setProperty("struts.freemarker.templatesCache.updateDelay", "0");
            }

            props.setProperty("devMode", "true");
        } else {
            props.setProperty("devMode", "false");
        }

    }
}

 從字面意義上來看alias就是更名的意思,我們打開它的源碼可以看到大概的功能就是:如果用戶在配置<bean>的時候已經配置了上面提到的類如ObjectFactory則將其name改爲“defult”,否則則會自動加載並且name爲”default“。

    protected void alias(Class type, String key, ContainerBuilder builder, Properties props) {
        this.alias(type, key, builder, props, Scope.SINGLETON);
    }
    //以ObjectFactory爲例,如果沒有類型爲 ObjectFactory.class,名字爲“default”的bean,則需要通過以下操作將這個bean的name屬性改爲“default”
    protected void alias(Class type, String key, ContainerBuilder builder, Properties props, Scope scope) {
        if (!builder.contains(type, "default")) {
            String foundName = props.getProperty(key, "struts");
            if (builder.contains(type, foundName)) {//已經存在了ObjectFactory,則直接改名
                LOG.trace("Choosing bean ({}) for ({})", foundName, type.getName());
                builder.alias(type, foundName, "default");
            } else {//不存在ObjectFactory則需要進行配置
                try {
                    //加載ObjectFactory並註冊到builder中
                    Class cls = ClassLoaderUtil.loadClass(foundName, this.getClass());
                    LOG.trace("Choosing bean ({}) for ({})", cls.getName(), type.getName());
                    builder.factory(type, cls, scope);
                } catch (ClassNotFoundException var8) {
                    LOG.trace("Choosing bean ({}) for ({}) to be loaded from the ObjectFactory", foundName, type.getName());
                    if (!"struts".equals(foundName)) {
                        if (ObjectFactory.class == type) {
                            throw new ConfigurationException("Cannot locate the chosen ObjectFactory implementation: " + foundName);
                        }

                        builder.factory(type, new AbstractBeanSelectionProvider.ObjectFactoryDelegateFactory(foundName, type), scope);
                    }
                }
            }
        } else {
            //無法別名bean類型(),已分配默認映射。
            LOG.warn("Unable to alias bean type ({}), default mapping already assigned.", type.getName());
        }

    }

 關鍵的一句應該是:

//無法別名bean類型(),已分配默認映射。
LOG.warn("Unable to alias bean type ({}), default mapping already assigned.", type.getName());

對應的convertIfExist應該也是將根據struts.properties中已經存在的fromKey屬性的值複製給新的toKey屬性的值(可能是新舊版本之間的更替)。

    protected void convertIfExist(LocatableProperties props, String fromKey, String toKey) {
        if (props.containsKey(fromKey)) {//把名爲fromKey的屬性的值賦值給名爲toKey的屬性
            props.setProperty(toKey, props.getProperty(fromKey));
        }

    }

第九步:創建container

            Container container = this.init_PreloadConfiguration();
            container.inject(this);

 對於Container個人現在還很迷糊。本文篇幅也較長了,所以還是單獨寫一遍作爲記錄。

Next:Container

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