struts2源码分析(三)(初始化)(上)

3、所有需要解析的配置文件的解析类全部放入ConfigurationManager中的containerProviders中之后
 1:Container container = init_PreloadConfiguration();
 这段代码,负责创建一个container对象,并初始化所有需要配置的文件信息;
 首先,该方法属于Dispatcher中的方法,该方法的主要内容如下:

 /**
     * 加载前进行的配置初始化
     * @return
     */
    private Container init_PreloadConfiguration() {
     //获取configuration
        ①Configuration config = configurationManager.getConfiguration();
        //从configuration中获取container的一个实例
        ②Container container = config.getContainer();
        //获取是否配置了国际化
        ③boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
        //定义是否需要重新装载资源绑定
        ④LocalizedTextUtil.setReloadBundles(reloadi18n);

        return container;
    }

 ①Configuration config = configurationManager.getConfiguration();
 调用ConfigurationManager的getConfiguration()方法获取一个Configuration的实例,该方法的主要内容如下:

 /**
     * 获取当前的xwork配置类。顺便一个DefaultConfiguration的实体对象将被返回
     */
    public synchronized Configuration getConfiguration() {
        //系统首次运行时,该对象为空
     if (configuration == null) {
      //创建一个新的DefaultConfiguration对象,并用其初始化Configuration
            setConfiguration(createConfiguration(defaultFrameworkBeanName));
            try {
             //调用DefaultConfiguration对象的reloadContainer方法;加载、解析所有配置文件
                configuration.reloadContainer(getContainerProviders());
            } catch (ConfigurationException e) {
                setConfiguration(null);
                throw new ConfigurationException("Unable to load configuration.", e);
            }
        } else {
         //重新加载配置文件如果配置文件里面指明要重新加载
            conditionalReload(configuration.getContainer());
        }
     //返回这个configuration实例
        return configuration;
    }

 代码setConfiguration(createConfiguration(defaultFrameworkBeanName));
 其中createConfiguration(defaultFrameworkBeanName)的具体代码如下

/**
     * 创建一个DefaultConfiguration对象
     * @param beanName 此时beanName为struts
     * @return
     */
    protected Configuration createConfiguration(String beanName) {
        return new DefaultConfiguration(beanName);
    } 

 在该方法里,调用DefaultConfiguration的构造方法如下:

 /**
     * 构造方法,传递一个DefaultBeanName;
     * 如果没传递的话,默认设置为xwork
     * @param defaultBeanName
     */
    public DefaultConfiguration(String defaultBeanName) {
        this.defaultFrameworkBeanName = defaultBeanName;
    }

 在这里设置了DefaultConfiguration的protected String defaultFrameworkBeanName;
 上述createConfiguration(String beanName)返回了一个DefaultConfiguration的实例,
 此时再调用ConfigurationManager中的setConfiguration把新实例化的DefaultConfiguration填充变量,该方法的具体代码如下:

 /**
     * 通过传递过来的参数DefaultConfiguration初始化configuration
     * @param configuration
     */
    public synchronized void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

 此时初始化

protected Configuration configuration;//这个变量为DefaultConfiguration 

 然后调用实例化之后的configuration的reloadContainer(getContainerProviders())方法,在该方法内部负责对配置文件进行加载和解析
 首先调用ConfigurationManager的getContainerProviders()返回containerProviders这个实例具体代码如下

 /**
     * 获取当前ConfigurationManager中包含的provider对象
     * @return the list of registered ConfigurationProvider objects
     * @see ConfigurationProvider
     */
    public List<ContainerProvider> getContainerProviders() {
        providerLock.lock();
        try {
         //理论上,不出意外的话,将直接返回containerProviders对象
            if (containerProviders.size() == 0) {
                containerProviders.add(new XWorkConfigurationProvider());//该类主要加载bean
                containerProviders.add(new XmlConfigurationProvider("xwork.xml", false));//加载xwork配置解析provider
            }

            return containerProviders;
        } finally {
            providerLock.unlock();
        }
    }

 此时返回containerProviders这个实例
 然后调用configuration的reloadContainer(List<ContainerProvider> containerProviders)方法,在这个方法里面,对所有的配置信息进行了解析该方法的具体内容如下:

 /**
     * @throws ConfigurationException
     */
    public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
        1)packageContexts.clear();//清空packageContexts
        2)loadedFileNames.clear();//清空loadedFileNames
        3)List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();

        4)ContainerProperties props = new ContainerProperties();//创建一个容器配置管理类,当前内部类
        5)ContainerBuilder builder = new ContainerBuilder();//创建一个ContainerBuilder对象
        6)Container bootstrap = createBootstrapContainer();//实例化一个Container对象,该对象是ContainerImpl的一个实例
        //循环每一个ContainterProvider,将他们各自对应的容器配置元素注册到ContainerBuilder中去,
        //这里,首先加载provider中的配置
        for (final ContainerProvider containerProvider : providers)
        {
   //containerProvider进行依赖注入,这部分代码放在后面的struts2的依赖注入进行介绍
            7)bootstrap.inject(containerProvider);
            //这里对于资源文件的处理分两步走
            //当前的this指DefaultConfiguration这个对象
            8)containerProvider.init(this);//第一步是初始化,即完成格式转换,如xml格式的转换为 document对象集合.
            //providers中存放的数据有以下内容:
            /**
             * 1、DefaultPropertiesProvider(default.properties),这个类的register运行结束之后,参数全部放入了props里面
             * 2、StrutsXmlConfigurationProvider(struts-defaults.xml);这个类中constant放入build中,bean放入props中
             * 3、StrutsXmlConfigurationProvider(struts-plugin.xml);这个类中constant放入build中,bean放入props中
             * 4、StrutsXmlConfigurationProvider(struts.xml);这个类中constatn放入build中,bean放入props中
             * 5、LegacyPropertiesConfigurationProvider;这个类中需要配置的参数放入build中
             * 6、加载用户配置的文件,一般情况下,未添加
             * 7、init_FilterInitParameters(添加在web.xml的Filter中配置的常量);把web.xml中的fileter中的参数放入props中
             * 8、BeanSelectionProvider;把配置放入builder中的factories中
             */
            9)containerProvider.register(builder, props);//第二步是将资源文件中配置的对象注册到容器构造者对象中去。
        }
        //把props中的参数放入builder中
        10)props.setConstants(builder);
        //在builder中添加一个Configuration
        11)builder.factory(Configuration.class, new Factory<Configuration>() {
            public Configuration create(Context context) throws Exception {
                return DefaultConfiguration.this;
            }
        });

        //获取当前线程的ActionContext
        12)ActionContext oldContext = ActionContext.getContext();
        try {
            // Set the bootstrap container for the purposes of factory creation

            13)setContext(bootstrap);
            14)container = builder.create(false);
            15)setContext(container);
            16)objectFactory = container.getInstance(ObjectFactory.class);//获取一个objectFactory实例

            // Process the configuration providers first
            // 首先执行providers配置
            for (final ContainerProvider containerProvider : providers)
            {
             /**
              * 解析xml中配置的package元素
              */
                if (containerProvider instanceof PackageProvider) {
                    17)container.inject(containerProvider);//进行依赖注入,这部分代码放在后面的struts2的依赖注入进行介绍
                    /**
                     * 1、DefaultPropertiesProvider(default.properties),这个类的loadPackages()方法不执行任何操作
                     * 2、StrutsXmlConfigurationProvider(struts-defaults.xml);这个类中的loadPackages()方法执行的结果解析了配置文件中的package元素并放入DefaultConfiguration元素的packageContexts中
                     * 3、StrutsXmlConfigurationProvider(struts-plugin.xml);这个类中的loadPackages()方法执行的结果解析了配置文件中的package元素并放入DefaultConfiguration元素的packageContexts中
                     * 4、StrutsXmlConfigurationProvider(struts.xml);这个类中的loadPackages()方法执行的结果解析了配置文件中的package元素并放入DefaultConfiguration元素的packageContexts中
                     * 5、LegacyPropertiesConfigurationProvider;这个类的loadPackages()方法不执行任何操作
                     * 6、加载用户配置的文件,一般情况下,未添加
                     * 7、init_FilterInitParameters;这个类的loadPackages()方法不执行任何操作
                     * 8、BeanSelectionProvider;这个类的loadPackages()方法不执行任何操作
                     */
                    18)((PackageProvider)containerProvider).loadPackages();//调用loadPackages方法
                    19)packageProviders.add((PackageProvider)containerProvider);
                }
            }

            // Then process any package providers from the plugins
            //让后执行plugins中的package providers
            20)Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);
            if (packageProviderNames != null) {
                for (String name : packageProviderNames) {
                    21)PackageProvider provider = container.getInstance(PackageProvider.class, name);
                    22)provider.init(this);
                    23)provider.loadPackages();
                    24)packageProviders.add(provider);
                }
            }

            25)rebuildRuntimeConfiguration();
        } finally {
            if (oldContext == null) {
                26)ActionContext.setContext(null);
            }
        }
        27)return packageProviders;
    }

  1)packageContexts.clear();//清空packageContexts
  该DefaultConfiguration中有

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


  这么一个属性在第一次加载时,先把这个属性中的内容清空
  map里面的PackageConfig(com.opensymphony.xwork2.config.entities)这个类是一个package的配置类,该类在xml的配置文件中,相当于package标签。该类的具体作用和用法将在下面讲到
  2)loadedFileNames.clear();//清空loadedFileNames,该参数用于记录已经加载的文件名
  该DefaultConfiguration中有

 protected Set<String> loadedFileNames = new TreeSet<String>();这么一个属性。在第一次加载时,先把这个属性中的内容清空 

  3)List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();
  创建一个PackageProvider(com.opensymphony.xwork2.config)的list;该PackageProvider是一个接口,该接口的主要内容如下

public interface PackageProvider {
    
    /**
     * 初始化配置信息
     * @param configuration The configuration
     * @throws ConfigurationException If anything goes wrong
     */
    public void init(Configuration configuration) throws ConfigurationException;
    
    /**
     * 告知该packageProvider是否需要重新加载
     *
     * @return <tt>true</tt>, whether the PackageProvider should reload its configuration, <tt>false</tt>otherwise.
     */
    public boolean needsReload();

    /**
     * 为配置加载该packageProvider
     * @throws ConfigurationException
     */
    public void loadPackages() throws ConfigurationException;
    
  }  

  该接口定义了3个方法,分别为init(Configuration configuration),needsReload(),loadPackages()
  4)ContainerProperties props = new ContainerProperties();//创建一个容器配置管理类,当前内部类
  创建一个ContainerProperties(当前DefaultConfiguration的内部类)的类,该类的主要代码如下

 /**
     * 容器配置类
     * 该类继承自LoctableProperites
     * @author Administrator
     *
     */
    class ContainerProperties extends LocatableProperties {
        private static final long serialVersionUID = -7320625750836896089L;

        @Override
        public Object setProperty(String key, String value) {
            String oldValue = getProperty(key);
            if (LOG.isInfoEnabled() && oldValue != null && !oldValue.equals(value) && !defaultFrameworkBeanName.equals(oldValue)) {
                LOG.info("Overriding property "+key+" - old value: "+oldValue+" new value: "+value);
            }
            return super.setProperty(key, value);
        }

        /**
         * 把builder中的
         * @param builder
         */
        public void setConstants(ContainerBuilder builder) {
            for (Object keyobj : keySet()) {
                String key = (String)keyobj;
    //这里调用了builder的方法,将在后面进行介绍
                builder.factory(String.class, key,
                        new LocatableConstantFactory<String>(getProperty(key), getPropertyLocation(key)));
            }
        }
    }

 该类继承自LocatableProperties(com.opensymphony.xwork2.util.location)这个类继承了Properties类,并实现了Locatable(com.opensymphony.xwork2.util.location)接口,
    Locatable接口的主要内容如下:

 public interface Locatable {
  /**
   * 得到这个对象的地址
   * @return 返回对象创建的地址
   */
  public Location getLocation();
 }

 5)ContainerBuilder builder = new ContainerBuilder();//创建一个ContainerBuilder对象
 调用ContainerBuilder(com.opensymphony.xwork2.inject)的默认无参构造方法,该方法具体内容如下:

 /**
    * 创建一个新的builder.
    */
   public ContainerBuilder() {
  // 在当前容器中作为默认容器的实现
  factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME), CONTAINER_FACTORY);

  // 注入的注入成员的日志记录
  factories.put(Key.newInstance(Logger.class, Container.DEFAULT_NAME), LOGGER_FACTORY);
   }  

 在该ContainerBuilder中有一个常量

final Map<Key<?>, InternalFactory<?>> factories = new HashMap<Key<?>, InternalFactory<?>>();

 该常量是构建容器所必须的。其内容组成是与具体运行环境有关,既有来自struts2框架本身的配置所提供的一些组成部分,又有来自客户项目的配置数据提供的组成部分
 其中Key中包含的是类的类型,名称和哈希值。InternalFactory代表的是生成类的工厂对象,调用其中的factory方法,就可以生成相应的对象
 Key(com.opensymphony.xwork2.inject)该类的代码如下:

/**
  * 依赖映射的关键。所需的类型和名称的唯一性标识。
  */
 class Key<T> {

   final Class<T> type;//类型
   final String name;//名称
   final int hashCode;//哈希值

   private Key(Class<T> type, String name) {
  if (type == null) {
    throw new NullPointerException("Type is null.");
  }
  if (name == null) {
    throw new NullPointerException("Name is null.");
  }

  this.type = type;
  this.name = name;

  hashCode = type.hashCode() * 31 + name.hashCode();
   }

   Class<T> getType() {
  return type;
   }

   String getName() {
  return name;
   }

   @Override
   public int hashCode() {
  return hashCode;
   }

   @Override
   public boolean equals(Object o) {
  if (!(o instanceof Key)) {
    return false;
  }
  if (o == this) {
    return true;
  }
  Key other = (Key) o;
  return name.equals(other.name) && type.equals(other.type);
   }

   @Override
   public String toString() {
  return "[type=" + type.getName() + ", name='" + name + "']";
   }

   static <T> Key<T> newInstance(Class<T> type, String name) {
  return new Key<T>(type, name);
   }
 } 

 InternalFactory(com.opensymphony.xwork2.inject)是一个接口,该接口的主要内容如下:

/**
  * 创建将要被注入的对象的实例化工厂
  */
 interface InternalFactory<T> extends Serializable {

   /**
    * 创建一个将要被注入的对象
    *
    * @param context of this injection
    * @return instance 将要被注入的类的实例
    */
   T create(InternalContext context);
 } 

 InternalContext(com.opensymphony.xwork2.inject)该类用于协调和支持循环依赖注入;该类的代码如下

 /**
  * 内部上下文。用于协调和支持循环依赖注入。
  */
 class InternalContext {

   final ContainerImpl container;
   final Map<Object, ConstructionContext<?>> constructionContexts = new HashMap<Object, ConstructionContext<?>>();
   Scope.Strategy scopeStrategy;
   ExternalContext<?> externalContext;

   InternalContext(ContainerImpl container) {
  this.container = container;
   }

   public Container getContainer() {
  return container;
   }

   ContainerImpl getContainerImpl() {
  return container;
   }

   Scope.Strategy getScopeStrategy() {
  if (scopeStrategy == null) {
    scopeStrategy = (Scope.Strategy) container.localScopeStrategy.get();

    if (scopeStrategy == null) {
   throw new IllegalStateException("Scope strategy not set. "
    + "Please call Container.setScopeStrategy().");
    }
  }

  return scopeStrategy;
   }

   @SuppressWarnings("unchecked")
   <T> ConstructionContext<T> getConstructionContext(Object key) {
  ConstructionContext<T> constructionContext =
   (ConstructionContext<T>) constructionContexts.get(key);
  if (constructionContext == null) {
    constructionContext = new ConstructionContext<T>();
    constructionContexts.put(key, constructionContext);
  }
  return constructionContext;
   }

   @SuppressWarnings("unchecked")
   <T> ExternalContext<T> getExternalContext() {
  return (ExternalContext<T>) externalContext;
   }

   void setExternalContext(ExternalContext<?> externalContext) {
  this.externalContext = externalContext;
   }
 }

 在创建ContainerBuilder的时候

 factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME), CONTAINER_FACTORY);//在factories中添加一个创建Container的工厂

 这行代码,向factory中添加了一个记录:Key.newInstance(Container.class, Container.DEFAULT_NAME)为一个Key的实例。其中Container.DEFAULT_NAME为default
 CONTAINER_FACTORY(为Container创建了一个工厂)为:

 private static final InternalFactory<Container> CONTAINER_FACTORY = new InternalFactory<Container>() {
        public Container create(InternalContext context) {
          return context.getContainer();
        }
      };
 factories.put(Key.newInstance(Logger.class, Container.DEFAULT_NAME), LOGGER_FACTORY);//在factories中添加一个创建Logger的工厂

 LOGGER_FACTORY(为Logger创建一个工厂)为:

 private static final InternalFactory<Logger> LOGGER_FACTORY = new InternalFactory<Logger>() {
        public Logger create(InternalContext context) {
          Member member = context.getExternalContext().getMember();//(未分析)
          return member == null ? Logger.getAnonymousLogger() : Logger.getLogger(member.getDeclaringClass().getName());(未分析)
        }
      };

  6)Container bootstrap = createBootstrapContainer();//实例化一个Container对象,该对象是ContainerImpl的一个实例
  在这里首先创建一个ContainerBuilder,利用该对象中的方法,初始化factories让后再创建一个ContainerImpl返回
  该方法属于DefaultConfiguration中的方法,其主要作用是创建一个Container对象。其代码如下:

   /**
     * 创建一个Container对象
     * @return
     */
    protected Container createBootstrapContainer() {
     /**
      * 首先生成一个ContainerBuilder对象,调用register来实现对builder
      * 对象的factories成员变量的设置
      */
        ContainerBuilder builder = new ContainerBuilder();
        /**
         * 对框架的扩展点的实现,完成框架功能必须,因此也需要加载,否则容器无法正常起效,
         * 以下这些扩展点暂时未分析
         */
   //ObjectFactory负责创建核心框架对象
        builder.factory(ObjectFactory.class, Scope.SINGLETON);
        //其中FileManager访问文件系统和文件的变化进行监测的基本接口
        //DefaultFileManager是FileManager接口的实现类
        builder.factory(FileManager.class, DefaultFileManager.class, Scope.SINGLETON);
        //未分析
        builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
        //ValueStackFactory值栈类接口,OgnlValueStackFactory值栈的实现类
        builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
        //xwork的类型转换器
        builder.factory(XWorkConverter.class, Scope.SINGLETON);
        //xwork的类型转换器
        builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
        //Collection类型转换器
        builder.factory(TypeConverter.class, "collection",  CollectionConverter.class, Scope.SINGLETON);
        //Array类型转换器
        builder.factory(TypeConverter.class, "array", ArrayConverter.class, Scope.SINGLETON);
        //Date类型转换器
        builder.factory(TypeConverter.class, "date", DateConverter.class, Scope.SINGLETON);
        //Number类型转换器
        builder.factory(TypeConverter.class, "number",  NumberConverter.class, Scope.SINGLETON);
        //String类型转换器
        builder.factory(TypeConverter.class, "string", StringConverter.class, Scope.SINGLETON);
        //文本类型转换器
        builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON);
        builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
        builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
        builder.factory(OgnlUtil.class, Scope.SINGLETON);
        builder.constant("devMode", "false");
        builder.constant("logMissingProperties", "false");
        /**
         * 参数收集完成,通过create实现容器的创建
         */
        return builder.create(true);
    }

 在这个方法里面涉及到ContainerBuilder的很多方法下面来对这些代码进行分析:

 public final class ContainerBuilder {
   /**
    * 
    * factories是构建容器所必须的,但其内容组成是与具体运行环境有关,既有来自struts2框架本身的
    * 配置所提供的一些组成部分,又有来自客户项目的配置数据提供的组成部分
    * 构造容器对象的时候的参数是一个个的键值对,
    * Key中包含的是类的类型,名称和哈希值
    * InternalFactory代表的是生成类的工厂对象,调用其中的factory方法,就可以生成相应的对象
    */
   final Map<Key<?>, InternalFactory<?>> factories = new HashMap<Key<?>, InternalFactory<?>>();
   /**
    * 创建将要被注入的单例模式对象的列表
    */
   final List<InternalFactory<?>> singletonFactories = new ArrayList<InternalFactory<?>>();
   final List<Class<?>> staticInjections = new ArrayList<Class<?>>();
   boolean created;//是否已被创建
   boolean allowDuplicates = false;
   //container_factory
   private static final InternalFactory<Container> CONTAINER_FACTORY = new InternalFactory<Container>() {
   public Container create(InternalContext context) {
     return context.getContainer();
   }
    };
   //logger_factory
   private static final InternalFactory<Logger> LOGGER_FACTORY = new InternalFactory<Logger>() {
   public Logger create(InternalContext context) {
     Member member = context.getExternalContext().getMember();
     return member == null ? Logger.getAnonymousLogger() : Logger.getLogger(member.getDeclaringClass().getName());
   }
    };

   /**
    * 创建一个新的builder.
    */
   public ContainerBuilder() {
  // 在当前容器中作为默认容器的实现
  factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME), CONTAINER_FACTORY);

  // 注入的注入成员的日志记录
  factories.put(Key.newInstance(Logger.class, Container.DEFAULT_NAME), LOGGER_FACTORY);
   }

   /**
    * 实现功能的主体。其它的factory方法主要是用来进行参数的适配和改造。
    */
   private <T> ContainerBuilder factory(final Key<T> key, InternalFactory<? extends T> factory, Scope scope) {
  ensureNotCreated();//用来确定该容器是否已经创建
  checkKey(key);//确认一个key是否已经映射了
  final InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory);//对工厂类的作用范围进行包装
  factories.put(key, scopedFactory);//把该工厂类放入factories中
  //如果该工厂类的作用范围为singleton
  if (scope == Scope.SINGLETON) {
    //把该工厂类进行装饰,放入单例模式对象的列表
    singletonFactories.add(new InternalFactory<T>() {
   public T create(InternalContext context) {
     try {
    context.setExternalContext(ExternalContext.newInstance(null, key, context.getContainerImpl()));
    return scopedFactory.create(context);
     } finally {
    context.setExternalContext(null);
     }
   }
    });
  }
  return this;
   }
   
   /**
    * 确定一个key是否已经映射了
    */
   private void checkKey(Key<?> key) {
  if (factories.containsKey(key) && !allowDuplicates) {
    throw new DependencyException("Dependency mapping for " + key + " already exists.");
  }
   }

   /**
    * 映射一个factory通过给定的依赖类型和名称
    *
    * @param type of dependency
    * @param name of dependency
    * @param factory creates objects to inject
    * @param scope scope of injected instances
    * @return this builder
    */
   public <T> ContainerBuilder factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope) {
    /**
     * 对传入的factory对象进行装饰
     */
  InternalFactory<T> internalFactory = new InternalFactory<T>() {

    public T create(InternalContext context) {
   try {
     Context externalContext = context.getExternalContext();
     return factory.create(externalContext);
   } catch (Exception e) {
     throw new RuntimeException(e);
   }
    }

    @Override
    public String toString() {
   return new LinkedHashMap<String, Object>() {{
     put("type", type);
     put("name", name);
     put("factory", factory);
   }}.toString();
    }
  };

  return factory(Key.newInstance(type, name), internalFactory, scope);
   }

   /**
    * 相当于调用factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope);
    */
   public <T> ContainerBuilder factory(Class<T> type, Factory<? extends T> factory, Scope scope) {
  return factory(type, Container.DEFAULT_NAME, factory, scope);
   }

   /**
    * 相当于调用factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope);
    */
   public <T> ContainerBuilder factory(Class<T> type, String name, Factory<? extends T> factory) {
  return factory(type, name, factory, Scope.DEFAULT);
   }

   /**
    * 相当于调用factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope);
    */
   public <T> ContainerBuilder factory(Class<T> type, Factory<? extends T> factory) {
  return factory(type, Container.DEFAULT_NAME, factory, Scope.DEFAULT);
   }

   /**
    * 映射一个给定依赖名字和类型的实现类,用container创建一个实例,递归依赖注入
    * @param type 依赖的类型
    * @param name 依赖的名称
    * @param implementation 实现类
    * @param scope 注入的作用范围
    * @return this builder
    */
   public <T> ContainerBuilder factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope) {
  // 这个工厂创建一个给定实现类的实例
  //对给定的implementation进行装饰
  InternalFactory<? extends T> factory = new InternalFactory<T>() {

    volatile ContainerImpl.ConstructorInjector<? extends T> constructor;

    @SuppressWarnings("unchecked")
    public T create(InternalContext context) {
   if (constructor == null) {
     this.constructor =
      context.getContainerImpl().getConstructor(implementation);
   }
   return (T) constructor.construct(context, type);
    }

    @Override
    public String toString() {
   return new LinkedHashMap<String, Object>() {{
     put("type", type);
     put("name", name);
     put("implementation", implementation);
     put("scope", scope);
   }}.toString();
    }
  };

  return factory(Key.newInstance(type, name), factory, scope);
   }

   /**
    * 映射一个给定依赖名字和类型的实现类,用container创建一个实例,递归依赖注入
    * <p>Sets scope to value from {@link Scoped} annotation on the
    * implementation class. Defaults to {@link Scope#DEFAULT} if no annotation
    * is found.
    *
    * @param type of dependency
    * @param name of dependency
    * @param implementation class
    * @return this builder
    */
   public <T> ContainerBuilder factory(final Class<T> type, String name, final Class<? extends T> implementation) {
  Scoped scoped = implementation.getAnnotation(Scoped.class);
  Scope scope = scoped == null ? Scope.DEFAULT : scoped.value();
  return factory(type, name, implementation, scope);
   }

   /**
    * 相当于调用 factory(final Class<T> type, String name, final Class<? extends T> implementation)
    */
   public <T> ContainerBuilder factory(Class<T> type, Class<? extends T> implementation) {
  return factory(type, Container.DEFAULT_NAME, implementation);
   }

   /**
    * 相当于调用 factory(final Class<T> type, String name, final Class<? extends T> implementation)
    */
   public <T> ContainerBuilder factory(Class<T> type) {
  return factory(type, Container.DEFAULT_NAME, type);
   }

   /**
    * 相当于调用 factory(final Class<T> type, String name, final Class<? extends T> implementation)
    */
   public <T> ContainerBuilder factory(Class<T> type, String name) {
  return factory(type, name, type);
   }

   /**
    * 相当于调用factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope)
    */
   public <T> ContainerBuilder factory(Class<T> type, Class<? extends T> implementation, Scope scope) {
  return factory(type, Container.DEFAULT_NAME, implementation, scope);
   }

   /**
    * 相当于调用factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope)
    */
   public <T> ContainerBuilder factory(Class<T> type, Scope scope) {
  return factory(type, Container.DEFAULT_NAME, type, scope);
   }

   /**
    * 相当于调用factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope)
    */
   public <T> ContainerBuilder factory(Class<T> type, String name, Scope scope) {
  return factory(type, name, type, scope);
   }
   
   /**
    * 相当于调用alias(Class<T> type, String alias)
    */
   public <T> ContainerBuilder alias(Class<T> type, String alias) {
  return alias(type, Container.DEFAULT_NAME, alias);
   }
   
   /**
    * 映射一个已存在的工厂一个新的名字
    * 
    * @param type of dependency
    * @param name of dependency
    * @param alias of to the dependency
    * @return this builder
    */
   public <T> ContainerBuilder alias(Class<T> type, String name, String alias) {
  return alias(Key.newInstance(type, name), Key.newInstance(type, alias));
   }
   
   /**
    * 映射一个现有的依赖关系。并替换key为aliasKey
    */
   private <T> ContainerBuilder alias(final Key<T> key, final Key<T> aliasKey) {
  ensureNotCreated();//判断该容器是否已经被创建
  checkKey(aliasKey);//判断该key是否已经存在
  
  //获取factories中指定key的对象
  final InternalFactory<? extends T> scopedFactory = (InternalFactory<? extends T>)factories.get(key);
  //如果该对象不存在,抛出异常
  if (scopedFactory == null) {
   throw new DependencyException("Dependency mapping for " + key + " doesn't exists.");
  }
  //把新的key,和对象放入aliasKey中
  factories.put(aliasKey, scopedFactory);
  return this;
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, String value) {
  return constant(String.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, int value) {
  return constant(int.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, long value) {
  return constant(long.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, boolean value) {
  return constant(boolean.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, double value) {
  return constant(double.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, float value) {
  return constant(float.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, short value) {
  return constant(short.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, char value) {
  return constant(char.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public ContainerBuilder constant(String name, Class value) {
  return constant(Class.class, name, value);
   }

   /**
    * 映射一个给定名称的常量值
    */
   public <E extends Enum<E>> ContainerBuilder constant(String name, E value) {
  return constant(value.getDeclaringClass(), name, value);
   }

   /**
    * 映射一个给定名称和类型的常量值.
    */
   private <T> ContainerBuilder constant(final Class<T> type, final String name, final T value) {
  //对给定值进行装饰
  InternalFactory<T> factory = new InternalFactory<T>() {
    public T create(InternalContext ignored) {
   return value;
    }

    @Override
    public String toString() {
   return new LinkedHashMap<String, Object>() {
     {
    put("type", type);
    put("name", name);
    put("value", value);
     }
   }.toString();
    }
  };
  return factory(Key.newInstance(type, name), factory, Scope.DEFAULT);
   }

   /**
    * 在创建时,容器将注入静态域和方法为给定的类。
    * @param types 将被注入的静态常量成员
    */
   public ContainerBuilder injectStatics(Class<?>... types) {
  staticInjections.addAll(Arrays.asList(types));
  return this;
   }

   /**
    * 如果factories中包含给定类型和名称的值,则返回true
    */
   public boolean contains(Class<?> type, String name) {
  return factories.containsKey(Key.newInstance(type, name));
   }

   /**
    * 相当于调用contains(Class<?> type, String name)
    */
   public boolean contains(Class<?> type) {
  return contains(type, Container.DEFAULT_NAME);
   }

   /**
    * Creates a {@link Container} instance. Injects static members for classes
    * which were registered using {@link #injectStatics(Class...)}.
    * 创建一个Container实例。
    * 
    * @param loadSingletons 如果 boolean created(loadSingletons)值为true 的话,先调用scope="singleton" 的对象工厂的create方法
    * @throws IllegalStateException if called more than once
    */
   public Container create(boolean loadSingletons) {
  ensureNotCreated();//判断是否已经创建
  created = true;//设置created为true
  final ContainerImpl container = new ContainerImpl(new HashMap<Key<?>, InternalFactory<?>>(factories));
  //把对象生命周期为单实例的对象先创建出来.  
  if (loadSingletons) {
    container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
   public Void call(InternalContext context) {
     for (InternalFactory<?> factory : singletonFactories) {
    factory.create(context);
     }
     return null;
   }
    });
  }
  //依赖注入
  container.injectStatics(staticInjections);
  //返回一个ContainerImpl实例对象
  return container;
   }

   /**
    * 现在我们只支持创造每一容器实例生成器。
    * 如果我们想支持创建每建造多个容器,我们要搬到一个“工厂”的模式,我们创建每个集装箱厂实例。
    * 现在,一个工厂的实例将在所有容器共享,单身人士对容器时延迟加载,等。
    */
   private void ensureNotCreated() {
  if (created) {
    throw new IllegalStateException("Container already created.");
  }
   }
   
   public void setAllowDuplicates(boolean val) {
    allowDuplicates = val;
   }

   /**
    * Implemented by classes which participate in building a container.
    */
   public interface Command {

  /**
   * Contributes factories to the given builder.
   *
   * @param builder
   */
  void build(ContainerBuilder builder);
   }
 }

  7)bootstrap.inject(containerProvider);
containerProvider进行依赖注入,这部分代码放在后面的struts2的依赖注入进行介绍 

  8)containerProvider.init(this);//这里是比较核心的一个模块
  首先确定当前的providers中有哪些记录
  1:DefaultPropertiesProvider(default.properties)
  执行DefaultPropertiesProvider该类的init(Configuration configuration)方法
  该类的该方法如下:

 /**
     * 不用把该对象转换成document对象
     */
    public void init(Configuration configuration) throws ConfigurationException {
    }

  2:StrutsXmlConfigurationProvider(struts-default.xml)
  该类没有对init方法进行重写,因此调用父类(XmlConfigurationProvider)的init方法

/**
     * @param configuration 为DefaultConfiguration对象的一个实例
     */
    public void init(Configuration configuration) {
        this.configuration = configuration;//设置configuration
        this.includedFileNames = configuration.getLoadedFileNames();//此时为空
        loadDocuments(configFileName);//第一次为loadDocuments(struts-defaults.xml)
    } 
 /**
     * @param configFileName struts-default.xml
     */
    private void loadDocuments(String configFileName) {
        try {
            loadedFileUrls.clear();
            documents = loadConfigurationFiles(configFileName, null);//把*.xml转换成document形式,并存放到documents中
        } catch (ConfigurationException e) {
            throw e;
        } catch (Exception e) {
            throw new ConfigurationException("Error loading configuration file " + configFileName, e);
        }
    }

 其中private Set<String> loadedFileUrls = new HashSet<String>();//已经加载的file的URL

/**
     * 返回*.xml的document形式结果
     * @param fileName struts-default.xml
     * @param includeElement null
     */
    private List<Document> loadConfigurationFiles(String fileName, Element includeElement) {
        List<Document> docs = new ArrayList<Document>();//创建一个新的List<dom>对象
        List<Document> finalDocs = new ArrayList<Document>();//再创建一个finalDocs的List<dom>对象
        if (!includedFileNames.contains(fileName)) {//如果includedFileNames不包含名为fileName的对象
            if (LOG.isDebugEnabled()) {
                LOG.debug("Loading action configurations from: " + fileName);
            }
            //把该fileName添加到includedFileNames,防止重复添加
            includedFileNames.add(fileName);
            
            Iterator<URL> urls = null;
            InputStream is = null;

            IOException ioException = null;
            try {
             /**
              * 获取fileName的URL
              */
                urls = getConfigurationUrls(fileName);
            } catch (IOException ex) {
                ioException = ex;
            }
            
            /**
             * 如果urls为空,或urls.hasNext = true,则执行下面的代码
             */
            if (urls == null || !urls.hasNext()) {
                if (errorIfMissing) {
                    throw new ConfigurationException("Could not open files of the name " + fileName, ioException);
                } else {
                    if (LOG.isInfoEnabled()) {
                    LOG.info("Unable to locate configuration files of the name "
                            + fileName + ", skipping");
                    }
                    return docs;//此时docs对象为空
                }
            }
            //否则
            URL url = null;
            while (urls.hasNext()) {
                try {
                 //把fileName的URL传递给url
                    url = urls.next();
                    //fileManager对象为DefaultFileManager,通过struts框架自动注入进来
     //根据URL加载指定的文件,并返回inputStream形式的结果
                    is = fileManager.loadFile(url);

                    InputSource in = new InputSource(is);

                    //设置此输入源的系统标识符
                    in.setSystemId(url.toString());

                    /**
                     * 在docs中添加一个document
                     */
                    docs.add(DomHelper.parse(in, dtdMappings));
                } catch (XWorkException e) {
                    if (includeElement != null) {
                        throw new ConfigurationException("Unable to load " + url, e, includeElement);
                    } else {
                        throw new ConfigurationException("Unable to load " + url, e);
                    }
                } catch (Exception e) {
                    final String s = "Caught exception while loading file " + fileName;
                    throw new ConfigurationException(s, e, includeElement);
                } finally {
                    if (is != null) {
                        try {
                            is.close();
                        } catch (IOException e) {
                            LOG.error("Unable to close input stream", e);
                        }
                    }
                }
            }
            
            //对documents进行排序,通过order这个属性
            Collections.sort(docs, new Comparator<Document>() {//(未分析)
                public int compare(Document doc1, Document doc2) {
                    return XmlHelper.getLoadOrder(doc1).compareTo(XmlHelper.getLoadOrder(doc2));
                }
            });

            /**
             * 对docs中的内容进行遍历
             */
            for (Document doc : docs) {
                Element rootElement = doc.getDocumentElement();
                NodeList children = rootElement.getChildNodes();
                int childSize = children.getLength();//struts-default.xml中有72个child;
                //对xml进行解析,查看其所有子元素中是否包含include元素
                for (int i = 0; i < childSize; i++) {
                    Node childNode = children.item(i);

                    if (childNode instanceof Element) {
                     //获取element
                        Element child = (Element) childNode;
                        //获取element的name
                        final String nodeName = child.getNodeName();
                        //如果element==include
                        if ("include".equals(nodeName)) {
                            String includeFileName = child.getAttribute("file");
                            if (includeFileName.indexOf('*') != -1) {
                                // handleWildCardIncludes(includeFileName, docs, child);
                                ClassPathFinder wildcardFinder = new ClassPathFinder();
                                wildcardFinder.setPattern(includeFileName);
                                Vector<String> wildcardMatches = wildcardFinder.findMatches();
                                for (String match : wildcardMatches) {
                                    finalDocs.addAll(loadConfigurationFiles(match, child));
                                }
                            } else {
                                finalDocs.addAll(loadConfigurationFiles(includeFileName, child));//递归调用,把所有include加载到finalDocs
                            }
                        }
                    }
                }
                finalDocs.add(doc);
                loadedFileUrls.add(url.toString());
            }

            if (LOG.isDebugEnabled()) {
                LOG.debug("Loaded action configuration from: " + fileName);
            }
        }
        return finalDocs;
    }

 /**
     * 获取fileName的Iterator<URL>
     * @param fileName
     * @return
     * @throws IOException
     */
    protected Iterator<URL> getConfigurationUrls(String fileName) throws IOException {
        return ClassLoaderUtil.getResources(fileName, XmlConfigurationProvider.class, false);
    }

至此,struts-default.xml已经转换成一个document对象放入docs中,接下来调用register再对转换好的docs中的内容进行解析

3:StrutsXmlConfigurationProvider(struts-plugin.xml)
  同2:
4:StrutsXmlConfigurationProvider(struts.xml)
  同2:

5:LegacyPropertiesConfigurationProvider
  该类的register中的代码具体如下:

   /**
     * 注册参数,把需要配置的参数放入builder对象的factories中
     */
    @SuppressWarnings("unchecked")
 public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {
        
     //获取一个Settings的实例
        final Settings settings = Settings.getInstance();
        
        loadSettings(props, settings);
        
        // Set default locale by lazily resolving the locale property as needed into a Locale object
        builder.factory(Locale.class, new Factory() {
            private Locale locale;

            public synchronized Object create(Context context) throws Exception {
                if (locale == null) {
                    String loc = context.getContainer().getInstance(String.class, StrutsConstants.STRUTS_LOCALE);
                    if (loc != null) {
                        StringTokenizer localeTokens = new StringTokenizer(loc, "_");
                        String lang = null;
                        String country = null;

                        if (localeTokens.hasMoreTokens()) {
                            lang = localeTokens.nextToken();
                        }

                        if (localeTokens.hasMoreTokens()) {
                            country = localeTokens.nextToken();
                        }
                        locale = new Locale(lang, country);
                    } else {
                        if (LOG.isInfoEnabled()) {
                            LOG.info("No locale define, substituting the default VM locale");
                        }
                        locale = Locale.getDefault();
                    }
                }
                return locale;
            }
        });
    }

6:用户配置
  具体代码具体分析
7:web.xml的filter中配置的参数

//把web.xml中配置的fileter中的参数放入props中
  public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
       props.putAll(initParams);
  }

8:BeanSelectionProvider

该类内部的register方法如下:

/**
     * 注册
     */
    public void register(ContainerBuilder builder, LocatableProperties props) {
    	/**
    	 * 把这些配置放入builder的factories中
    	 */
        alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props);
        alias(FileManager.class, StrutsConstants.STRUTS_FILEMANAGER, builder, props);
        alias(XWorkConverter.class, StrutsConstants.STRUTS_XWORKCONVERTER, builder, props);
        alias(TextProvider.class, StrutsConstants.STRUTS_XWORKTEXTPROVIDER, builder, props, Scope.DEFAULT);
        alias(ActionProxyFactory.class, StrutsConstants.STRUTS_ACTIONPROXYFACTORY, builder, props);
        alias(ObjectTypeDeterminer.class, StrutsConstants.STRUTS_OBJECTTYPEDETERMINER, builder, props);
        alias(ActionMapper.class, StrutsConstants.STRUTS_MAPPER_CLASS, builder, props);
        alias(MultiPartRequest.class, StrutsConstants.STRUTS_MULTIPART_PARSER, builder, props, Scope.DEFAULT);
        alias(FreemarkerManager.class, StrutsConstants.STRUTS_FREEMARKER_MANAGER_CLASSNAME, builder, props);
        alias(VelocityManager.class, StrutsConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME, builder, props);
        alias(UrlRenderer.class, StrutsConstants.STRUTS_URL_RENDERER, builder, props);
        alias(ActionValidatorManager.class, StrutsConstants.STRUTS_ACTIONVALIDATORMANAGER, builder, props);
        alias(ValueStackFactory.class, StrutsConstants.STRUTS_VALUESTACKFACTORY, builder, props);
        alias(ReflectionProvider.class, StrutsConstants.STRUTS_REFLECTIONPROVIDER, builder, props);
        alias(ReflectionContextFactory.class, StrutsConstants.STRUTS_REFLECTIONCONTEXTFACTORY, builder, props);
        alias(PatternMatcher.class, StrutsConstants.STRUTS_PATTERNMATCHER, builder, props);
        alias(StaticContentLoader.class, StrutsConstants.STRUTS_STATIC_CONTENT_LOADER, builder, props);
        alias(UnknownHandlerManager.class, StrutsConstants.STRUTS_UNKNOWN_HANDLER_MANAGER, builder, props);
        alias(UrlHelper.class, StrutsConstants.STRUTS_URL_HELPER, builder, props);

        /**
         * 判断props中的devMode是否为true
         */
        if ("true".equalsIgnoreCase(props.getProperty(StrutsConstants.STRUTS_DEVMODE))) {
        	//设置国际化
            props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, "true");
            props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "true");
            props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE, "false");
            props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY, "0");
            // Convert struts properties into ones that xwork expects
            props.setProperty("devMode", "true");
        } else {
            props.setProperty("devMode", "false");
        }

        //把struts2的properties转换成xwork的properties
        convertIfExist(props, StrutsConstants.STRUTS_LOG_MISSING_PROPERTIES, "logMissingProperties");
        convertIfExist(props, StrutsConstants.STRUTS_ENABLE_OGNL_EXPRESSION_CACHE, "enableOGNLExpressionCache");
        convertIfExist(props, StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "allowStaticMethodAccess");

        LocalizedTextUtil.addDefaultResourceBundle("org/apache/struts2/struts-messages");
        //加载用户资源绑定
        loadCustomResourceBundles(props);
    }


在这个方法内部调用了该类的alias方法,该方法具体如下:

/**
     * 调用该类的alias(Class type, String key, ContainerBuilder builder, Properties props, Scope scope)方法,同时传递scope为single
     * @param type
     * @param key
     * @param builder
     * @param props
     */
    void alias(Class type, String key, ContainerBuilder builder, Properties props) {
        alias(type, key, builder, props, Scope.SINGLETON);
    }

接着调用另一个alias方法,该方法具体如下:

/**
     * 把参数放入builder中
     * @param type class类型
     * @param key 
     * @param builder
     * @param props
     * @param scope
     */
    void alias(Class type, String key, ContainerBuilder builder, Properties props, Scope scope) {
    	//判断builder中是否存在指定type的参数
        if (!builder.contains(type)) {
        	/**
        	 * 从props中获取指定key和默认值的字符串
        	 */
            String foundName = props.getProperty(key, DEFAULT_BEAN_NAME);
            //检测builder中是否包含该type和指定默认值的配置
            if (builder.contains(type, foundName)) {
                if (LOG.isInfoEnabled()) {
                    LOG.info("Choosing bean (#0) for (#1)", foundName, type.getName());
                }
                //重新加载到builder中
                builder.alias(type, foundName, Container.DEFAULT_NAME);
            } else {
                try {
                	//反射生成class
                    Class cls = ClassLoaderUtil.loadClass(foundName, this.getClass());
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Choosing bean (#0) for (#1)", cls.getName(), type.getName());
                    }
                    //把cls添加到builder中的factories中
                    builder.factory(type, cls, scope);
                } catch (ClassNotFoundException ex) {
                    // Perhaps a spring bean id, so we'll delegate to the object factory at runtime
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Choosing bean (#0) for (#1) to be loaded from the ObjectFactory", foundName, type.getName());
                    }
                    if (DEFAULT_BEAN_NAME.equals(foundName)) {
                        // Probably an optional bean, will ignore
                    } else {
                        if (ObjectFactory.class != type) {
                            builder.factory(type, new ObjectFactoryDelegateFactory(foundName, type), scope);
                        } else {
                            throw new ConfigurationException("Cannot locate the chosen ObjectFactory implementation: " + foundName);
                        }
                    }
                }
            }
        } else {
            if (LOG.isWarnEnabled()) {
        	    LOG.warn("Unable to alias bean type (#0), default mapping already assigned.", type.getName());
            }
        }
    }

ContainerBuilder的代码在上面已经给出了分析,因此在这里不对其方法再次进行介绍。

10)props.setConstants(builder);

调用ContainerProperties的setConstants(ContainerBuilder builder)方法,把props中的信息放入ContainerBuilder的factories中;具体代码在上面已经展示过了

11)这行代码调用了ContainerBuilder的factory方法,向其factories中添加了一个Configuration的工厂类,该类的实例化为一个DefaultConfiguration对象

builder.factory(Configuration.class, new Factory<Configuration>() {
            public Configuration create(Context context) throws Exception {
                return DefaultConfiguration.this;
            }
        });
发布了39 篇原创文章 · 获赞 0 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章