struts源码之三

在init初始化方法中我们看到这样一句

 InitOperations init = new InitOperations();

这个类没什么作用,就是一个辅助类,来完成初始化的操作。

继续往下看

FilterHostConfig config = new FilterHostConfig(filterConfig);
            init.initLogging(config);
            Dispatcher dispatcher = init.initDispatcher(config);
            init.initStaticContentLoader(config, dispatcher);

 创建了FilterHostConfig,这个类也没什么作用就是包装FilterConfig

用官方的原话说

Host configuration that wraps FilterConfig

通过传入一个filterConfig完成该类的初始化。

public class FilterHostConfig implements HostConfig {

    private FilterConfig config;

    public FilterHostConfig(FilterConfig config) {
        this.config = config;
    }
    public String getInitParameter(String key) {
        return config.getInitParameter(key);
    }

    public Iterator<String> getInitParameterNames() {
        return MakeIterator.convert(config.getInitParameterNames());
    }

    public ServletContext getServletContext() {
        return config.getServletContext();
    }
}

 

该类处理完成,真正的初始化才开始,通过初始化辅助类InitOperations来完成初始化。

首先初始化日志信息

 init.initLogging(config);

 public void initLogging( HostConfig filterConfig ) {
        String factoryName = filterConfig.getInitParameter("loggerFactory");
        if (factoryName != null) {
            try {
                Class cls = ClassLoaderUtil.loadClass(factoryName, this.getClass());
                LoggerFactory fac = (LoggerFactory) cls.newInstance();
                LoggerFactory.setLoggerFactory(fac);
            } catch ( InstantiationException e ) {
                System.err.println("Unable to instantiate logger factory: " + factoryName + ", using default");
                e.printStackTrace();
            } catch ( IllegalAccessException e ) {
                System.err.println("Unable to access logger factory: " + factoryName + ", using default");
                e.printStackTrace();
            } catch ( ClassNotFoundException e ) {
                System.err.println("Unable to locate logger factory class: " + factoryName + ", using default");
                e.printStackTrace();
            }
        }
    }

 

通过代码我们可以清晰的看到factoryName一定是空的,因为我们压根就没在web.xml中配置factoryName.

所以里面的方法一定不执行。

直接返回。

 

接下来进入到Dispatcher dispatcher = init.initDispatcher(config);

初始化并创建Dispatcher

Dispatcher是struts2的核心类,完成大部分任务调度,所有的请求共享这一实例。

 

 public Dispatcher initDispatcher( HostConfig filterConfig ) {
        Dispatcher dispatcher = createDispatcher(filterConfig);
        dispatcher.init();
        return dispatcher;
    }

 

通过代码也可以看到Dispatcher是先创建,然后初始化。

它的创建很简单

private Dispatcher createDispatcher( HostConfig filterConfig ) {
        Map<String, String> params = new HashMap<String, String>();
        for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
            String name = (String) e.next();
            String value = filterConfig.getInitParameter(name);
            params.put(name, value);
        }
        return new Dispatcher(filterConfig.getServletContext(), params);
    }

 

把web.xml 中所有的配置信息取出来,放入一个hashmap中,然后存入Dispatcher中。就这样,完了

然后进入初始化,这个有点点复杂

 

public void init() {

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

        try {
            init_DefaultProperties(); // [1]
            init_TraditionalXmlConfigurations(); // [2]
            init_LegacyStrutsProperties(); // [3]
            init_CustomConfigurationProviders(); // [5]
            init_FilterInitParameters() ; // [6]
            init_AliasStandardObjects() ; // [7]

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

            if (!dispatcherListeners.isEmpty()) {
                for (DispatcherListener l : dispatcherListeners) {
                    l.dispatcherInitialized(this);
                }
            }
        } catch (Exception ex) {
            if (LOG.isErrorEnabled())
                LOG.error("Dispatcher initialization failed", ex);
            throw new StrutsException(ex);
        }
    }

 

通过代码可以看到,初始化做了很多事,首先是创建configurationManager

protected ConfigurationManager createConfigurationManager(String name) {
        return new ConfigurationManager(name);
    }

 

直接new一个configurationManager出来。默认的名称就是struts

 

初始化属性读取的类

 private void init_DefaultProperties() {
        configurationManager.addContainerProvider(new DefaultPropertiesProvider());
    }

 

以下所有的都一样,将所有的provider初始化,所有的Provider实现类都实现了ConfigurationProvider这个接口。

ConfigurationProvider这个接口又干嘛呢?

public interface ConfigurationProvider extends ContainerProvider, PackageProvider {
}

 

通过代码可以看到核心不在这里,在ContainerProvider和PackageProvider,

这里需要说的是ContainerProvider是容器的初始化,PackageProvider是包的初始化.

什么是容器呢?在struts2中constants/properties配置的信息就是容器的相关信息

PackageProvider就是包的信息,比如我们的struts.xml

 

回到初始化代码中,DefaultPropertiesProvider就是提供了一个读取默认的struts.properties的实现类。

好了,继续初始化操作。

初始化init_TraditionalXmlConfigurations

 

 private void init_TraditionalXmlConfigurations() {
        String configPaths = initParams.get("config");
        if (configPaths == null) {
            configPaths = DEFAULT_CONFIGURATION_PATHS;
        }
        String[] files = configPaths.split("\\s*[,]\\s*");
        for (String file : files) {
            if (file.endsWith(".xml")) {
                if ("xwork.xml".equals(file)) {
                    configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
                } else {
                    configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
                }
            } else {
                throw new IllegalArgumentException("Invalid configuration file name");
            }
        }
    }

 这里提供了俩种初始化配置文件的方法,当然他也提供了选择String configPaths = initParams.get("config");

但是我们在web.xml中没配置,所有默认的一定是struts,而不是xwork

protected XmlConfigurationProvider createStrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
        return new StrutsXmlConfigurationProvider(filename, errorIfMissing, ctx);
    }

 

configPaths = DEFAULT_CONFIGURATION_PATHS;

这里我们可以得到证明

 private static final String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";

 

继续往里面看,我们看到

 public StrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
        super(filename, errorIfMissing);
        this.servletContext = ctx;
        this.filename = filename;
        reloadKey = "configurationReload-"+filename;
        Map<String,String> dtdMappings = new HashMap<String,String>(getDtdMappings());
        dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.0//EN", "struts-2.0.dtd");
        dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1//EN", "struts-2.1.dtd");
        dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");
        dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.3//EN", "struts-2.3.dtd");
        setDtdMappings(dtdMappings);
        File file = new File(filename);
        if (file.getParent() != null) {
            this.baseDir = file.getParentFile();
        }
    }

 加入了struts配置文件的验证dtd,在后续会讲

 

完成了struts配置文件的初始化,继续初始化

init_LegacyStrutsProperties

 private void init_LegacyStrutsProperties() {
        configurationManager.addContainerProvider(new LegacyPropertiesConfigurationProvider());
    }

 

LegacyPropertiesConfigurationProvider这个初始化又干嘛呢?这个初始化主要完成除去上面初始化剩下的其他配置信息想初始化。

init_CustomConfigurationProviders();这个初始化很关键

以上的初始化都说初始化struts框架的配置信息,而这个初始化就是初始化我们在开发中写的配置文件

private void init_CustomConfigurationProviders() {
        String configProvs = initParams.get("configProviders");
        if (configProvs != null) {
            String[] classes = configProvs.split("\\s*[,]\\s*");
            for (String cname : classes) {
                try {
                    Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
                    ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
                    configurationManager.addContainerProvider(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);
                }
            }
        }
    }

 

通过代码可以看到,通过类加载器加载上来,然后放入configurationManager中。

 

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

 

 

这个初始化是初始化扩展框架的插件信息。

 

然后初始化一个容器

 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);

        return container;
    }

 

struts2的容器用来实现依赖注入和控制反转,定义如下

public interface Container extends Serializable {

  /**
   * Default dependency name.
   */
  String DEFAULT_NAME = "default";

  /**
   * Injects dependencies into the fields and methods of an existing object.
   */
  void inject(Object o);

  /**
   * Creates and injects a new instance of type {@code implementation}.
   */
  <T> T inject(Class<T> implementation);

  /**
   * Gets an instance of the given dependency which was declared in
   * {@link com.opensymphony.xwork2.inject.ContainerBuilder}.
   */
  <T> T getInstance(Class<T> type, String name);

  /**
   * Convenience method.&nbsp;Equivalent to {@code getInstance(type,
   * DEFAULT_NAME)}.
   */
  <T> T getInstance(Class<T> type);
  
  /**
   * Gets a set of all registered names for the given type
   * @param type The instance type
   * @return A set of registered names
   */
  Set<String> getInstanceNames(Class<?> type);

  /**
   * Sets the scope strategy for the current thread.
   */
  void setScopeStrategy(Scope.Strategy scopeStrategy);

  /**
   * Removes the scope strategy for the current thread.
   */
  void removeScopeStrategy();
}

 

 

未完待续

你可能感兴趣的:(struts)