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

12)ActionContext oldContext = ActionContext.getContext();
  获取ActionContext的实例。ActionContext的具体方法如下所示:

/**
     * 返回特定于当前线程的ActionContext
     * @return ActionContext 当前线程的ActionContext
     */
    public static ActionContext getContext() {
        return (ActionContext) actionContext.get();
    }    

 13)setContext(bootstrap);
  调用DefaultConfiguration的setContext(Container cont)方法,其中bootstrap是一个ContainerImpl类的实例,该方法具体内容如下:

  /**
     * 判断当前ActoinContext的getContext是否存在,如果不存在则创建一个并返回
     * @param cont
     * @return
     */
    protected ActionContext setContext(Container cont) {
     //获取当前ActionContext
        ActionContext context = ActionContext.getContext();
        //判断当前ActionContext是否为空
        if (context == null) {
         //若为空的话,则新建一个放入ActionContext中(ValueStack未分析)
            ValueStack vs = cont.getInstance(ValueStackFactory.class).createValueStack();//从ContainerBuilder中获取一个创建ValueStack的工厂类,并创建一个ValueStack实例
            context = new ActionContext(vs.getContext());//创建一个新的ActionContext对象
            ActionContext.setContext(context);//添加到ActionContext中
        }
        return context;//返回当前的ActionContext
    }  

  14)container = builder.create(false);
  调用的是ContainerBuilder中的create方法创建一个Container对象,该方法在上面已经对其进行过介绍。
  15)setContext(container);
  把container添加到ActionContext中该方法与13)一样
  16)objectFactory = container.getInstance(ObjectFactory.class);//获取一个objectFactory实例
  17)container.inject(containerProvider);//注入到容器中
  18)((PackageProvider)containerProvider).loadPackages();//调用loadPackages方法
  1:DefaultPropertiesProvider(default.properties)
  该类中为覆盖父类中的loadPackages()方法,此时调用父类中的loadPackages()方法如下

/**
     * 加载包,但是在该类里面不执行
     */
    public void loadPackages() throws ConfigurationException {
    } 

  2:StrutsXmlConfigurationProvider(struts-default.xml)
  该类中的loadPackages()方法如下:

/* (non-Javadoc)
     * @see com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#init(com.opensymphony.xwork2.config.Configuration)
     */
    @Override
    public void loadPackages() {
        ActionContext ctx = ActionContext.getContext();
        ctx.put(reloadKey, Boolean.TRUE);//向ActionContext中添加一个一个Map
        super.loadPackages();//调用父类的loadPackages()方法
    } 

 父类XmlConfigurationProvider中的loadPackages()方法如下:

 /**
     * 对*.xml中的package进行解析
     */
    public void loadPackages() throws ConfigurationException {
        List<Element> reloads = new ArrayList<Element>();
        //对documents进行遍历
        for (Document doc : documents) {
            Element rootElement = doc.getDocumentElement();//获取根元素
            NodeList children = rootElement.getChildNodes();//获取所有子节点
            int childSize = children.getLength();//获取子节点的长度

            /**
             * 对子节点进行遍历
             */
            for (int i = 0; i < childSize; i++) {
                Node childNode = children.item(i);//获取第I个子节点

                if (childNode instanceof Element) {
                    Element child = (Element) childNode;//把节点转换成元素

                    final String nodeName = child.getNodeName();//获取元素的name

                    //如果该元素名为package
                    if ("package".equals(nodeName)) {
                        ①PackageConfig cfg = addPackage(child);//解析该节点,并把解析之后的信息放入DefulatConfiguration中的packageContexts中
                        if (cfg.isNeedsRefresh()) {
                            ②reloads.add(child);
                        }
                    }
                }
            }
            ③loadExtraConfiguration(doc);
        }

        if (reloads.size() > 0) {
            ④reloadRequiredPackages(reloads);
        }

        for (Document doc : documents) {
            ⑤loadExtraConfiguration(doc);
        }
        //清空documents
        documents.clear();
        configuration = null;//设置configuration为空
    }

 ①PackageConfig cfg = addPackage(child);//解析该节点,并把解析之后的信息放入DefulatConfiguration中的packageContexts中
 在这里先看了解一些重要的类
 ResultConfig(com.opensymphony.xwork2.config.entities)类

 /**
  * 结果的配置,在xml的配置文件中像定义一个result标签一样
  */
 public class ResultConfig extends Located implements Serializable {

  protected Map<String,String> params;//参数
  protected String className;//结果名
  protected String name;//结果名称

  /**
   * 根据给定的name和className实例化一个ResultConfig对象
   * @param name 结果名称
   * @param className 结果名
   */
  protected ResultConfig(String name, String className) {
   this.name = name;
   this.className = className;
   params = new LinkedHashMap<String, String>();
  }

  /**
   * 根据给定的一个ResultConfig对象复制一个新的对象
   * @param orig
   */
  protected ResultConfig(ResultConfig orig) {
   this.params = orig.params;
   this.name = orig.name;
   this.className = orig.className;
  }

  /**
   * 获取className
   * @return
   */
  public String getClassName() {
   return className;
  }

  /**
   * 获取name
   * @return
   */
  public String getName() {
   return name;
  }

  /**
   * 获取param
   * @return
   */
  public Map<String,String> getParams() {
   return params;
  }

  @Override
  public boolean equals(Object o) {
   if (this == o) {
    return true;
   }

   if (!(o instanceof ResultConfig)) {
    return false;
   }

   final ResultConfig resultConfig = (ResultConfig) o;

   if ((className != null) ? (!className.equals(resultConfig.className)) : (resultConfig.className != null)) {
    return false;
   }

   if ((name != null) ? (!name.equals(resultConfig.name)) : (resultConfig.name != null)) {
    return false;
   }

   if ((params != null) ? (!params.equals(resultConfig.params)) : (resultConfig.params != null)) {
    return false;
   }

   return true;
  }

  @Override
  public int hashCode() {
   int result;
   result = ((name != null) ? name.hashCode() : 0);
   result = (29 * result) + ((className != null) ? className.hashCode() : 0);
   result = (29 * result) + ((params != null) ? params.hashCode() : 0);

   return result;
  }

  /**
   * 这个类的builder方法。唯一创建该类的实例的方法。目的是为了维持执行对象的不变性。
   * 该方式是通过结构化的方式来至此chain方式。设置完需要的参数之后,可以调用build方法创建一个实例
   */
  public static final class Builder {
   protected ResultConfig target;//创建一个对象

   /**
    * 实例化该对象
    * @param name
    * @param className
    */
   public Builder(String name, String className) {
    target = new ResultConfig(name, className);
   }

   /**
    * 复制一个该对象
    * @param orig
    */
   public Builder(ResultConfig orig) {
    target = new ResultConfig(orig);
   }

   /**
    * 设定该对象的名称
    * @param name
    * @return
    */
   public Builder name(String name) {
    target.name = name;
    return this;
   }

   /**
    * 设定该对象的结果明
    * @param name
    * @return
    */
   public Builder className(String name) {
    target.className = name;
    return this;
   }

   /**
    * 添加一个参数
    * @param name
    * @param value
    * @return
    */
    public Builder addParam(String name, String value) {
    target.params.put(name, value);
    return this;
   }
    
   /**
    * 添加一个map类型的参数集合
    * @param params
    * @return
    */
   public Builder addParams(Map<String,String> params) {
    target.params.putAll(params);
    return this;
   }

   /**
    * 设置该对象的location
    * @param loc
    * @return
    */
   public Builder location(Location loc) {
    target.location = loc;
    return this;
   }

   /**
    * 创建该对象
    * @return
    */
   public ResultConfig build() {
    embalmTarget();
    ResultConfig result = target;
    target = new ResultConfig(target);
    return result;
   }

   protected void embalmTarget() {
    target.params = Collections.unmodifiableMap(target.params);
   }
  }
 }

  InterceptorMapping(com.opensymphony.xwork2.config.entities)

 /**
  * 拦截器Mapping
  */
 public class InterceptorMapping implements Serializable {

  private String name;//拦截器名
  private Interceptor interceptor;//拦截器实现类

  public InterceptorMapping(String name, Interceptor interceptor) {
   this.name = name;
   this.interceptor = interceptor;
  }

  public String getName() {
   return name;
  }

  public Interceptor getInterceptor() {
   return interceptor;
  }

  @Override
  public boolean equals(Object o) {
   if (this == o) return true;
   if (o == null || getClass() != o.getClass()) return false;

   final InterceptorMapping that = (InterceptorMapping) o;

   if (name != null ? !name.equals(that.name) : that.name != null) return false;

   return true;
  }

  @Override
  public int hashCode() {
   int result;
   result = (name != null ? name.hashCode() : 0);
   return result;
  }
 }

 ExceptionMappingConfig(com.opensymphony.xwork2.config.entities)

/**
  * 异常映射的配置
  */
 public class ExceptionMappingConfig extends Located implements Serializable {

  protected String name;//名称
  protected String exceptionClassName;//异常类名称
  protected String result;//结果
  protected Map<String,String> params;//参数

  /**
   * 初始化一个ExceptionMappingConfig对象
   * @param name 名称
   * @param exceptionClassName 异常类名称
   * @param result 结果
   */
  protected ExceptionMappingConfig(String name, String exceptionClassName, String result) {
   this.name = name;
   this.exceptionClassName = exceptionClassName;
   this.result = result;
   this.params = new LinkedHashMap<String,String>();
  }

  /**
   * 根据现有的一个ExceptionMappingConfig实例化一个新的ExceptionMappingConfig对象
   * @param target
   */
  protected ExceptionMappingConfig(ExceptionMappingConfig target) {
   this.name = target.name;
   this.exceptionClassName = target.exceptionClassName;
   this.result = target.result;
   this.params = new LinkedHashMap<String,String>(target.params);
  }

  /**
   * 获取名称
   * @return
   */
  public String getName() {
   return name;
  }

  /**
   * 获取异常类名称
   * @return
   */
  public String getExceptionClassName() {
   return exceptionClassName;
  }

  /**
   * 获取结果
   * @return
   */
  public String getResult() {
   return result;
  }

  /**
   * 获取参数集合
   * @return
   */
  public Map<String,String> getParams() {
   return params;
  }

  @Override
  public boolean equals(Object o) {
   if (this == o) {
    return true;
   }

   if (!(o instanceof ExceptionMappingConfig)) {
    return false;
   }

   final ExceptionMappingConfig exceptionMappingConfig = (ExceptionMappingConfig) o;

   if ((name != null) ? (!name.equals(exceptionMappingConfig.name)) : (exceptionMappingConfig.name != null)) {
    return false;
   }

   if ((exceptionClassName != null) ? (!exceptionClassName.equals(exceptionMappingConfig.exceptionClassName)) : (exceptionMappingConfig.exceptionClassName != null))
   {
    return false;
   }

   if ((result != null) ? (!result.equals(exceptionMappingConfig.result)) : (exceptionMappingConfig.result != null))
   {
    return false;
   }

   if ((params != null) ? (!params.equals(exceptionMappingConfig.params)) : (exceptionMappingConfig.params != null))
   {
    return false;
   }

   return true;
  }

  @Override
  public int hashCode() {
   int hashCode;
   hashCode = ((name != null) ? name.hashCode() : 0);
   hashCode = (29 * hashCode) + ((exceptionClassName != null) ? exceptionClassName.hashCode() : 0);
   hashCode = (29 * hashCode) + ((result != null) ? result.hashCode() : 0);
   hashCode = (29 * hashCode) + ((params != null) ? params.hashCode() : 0);

   return hashCode;
  }

  /**
   * 这个类的builder方法。唯一创建该类的实例的方法。目的是为了维持执行对象的不变性。
   * 该方式是通过结构化的方式来至此chain方式。设置完需要的参数之后,可以调用build方法创建一个实例
   */
  public static class Builder{

   /**
    * 声明一个ExceptionMappingConfig实例
    */
   protected ExceptionMappingConfig target;

   /**
    * 根据现有的实例克隆一个target对象
    * @param toClone
    */
   public Builder(ExceptionMappingConfig toClone) {
    target = new ExceptionMappingConfig(toClone);
   }

   /**
    * 利用构造方法创建一个target对象
    * @param name
    * @param exceptionClassName
    * @param result
    */
   public Builder(String name, String exceptionClassName, String result) {
    target = new ExceptionMappingConfig(name, exceptionClassName, result);
   }

   /**
    * 设置名称
    * @param name
    * @return
    */
   public Builder name(String name) {
    target.name = name;
    return this;
   }

   /**
    * 设置异常类名称
    * @param name
    * @return
    */
   public Builder exceptionClassName(String name) {
    target.exceptionClassName = name;
    return this;
   }

   /**
    * 设置结果
    * @param result
    * @return
    */
   public Builder result(String result) {
    target.result = result;
    return this;
   }

   /**
    * 添加参数
    * @param name
    * @param value
    * @return
    */
   public Builder addParam(String name, String value) {
    target.params.put(name, value);
    return this;
   }

   /**
    * 添加一个map类型
    * @param params
    * @return
    */
   public Builder addParams(Map<String,String> params) {
    target.params.putAll(params);
    return this;
   }

   public Builder location(Location loc) {
    target.location = loc;
    return this;
   }
   
   /**
    * 创建该ExceptionMappingConfig对象
    * @return
    */
   public ExceptionMappingConfig build() {
    embalmTarget();
    ExceptionMappingConfig result = target;
    target = new ExceptionMappingConfig(target);
    return result;
   }

   protected void embalmTarget() {
    target.params = Collections.unmodifiableMap(target.params);
   }
  }

 } 

 ResultTypeConfig(com.opensymphony.xwork2.config.entities)

 /**
  * 返回结果类型的配置,在xml的配置文件中这相当于定义一个result-type类型
  */
 public class ResultTypeConfig extends Located implements Serializable {

  protected String className;//类名
  protected String name;//类型名称
  protected String defaultResultParam;//默认的结果参数
  protected Map<String,String> params;//参数集

  /**
   * 默认构造方法,在这里初始化该类的一些参数
   * @param name
   * @param className
   */
  protected ResultTypeConfig(String name, String className) {
   this.name = name;
   this.className = className;
   params = new LinkedHashMap<String,String>();
  }

  /**
   * 根据现有的一个该类的实例克隆一个新的对象
   * @param orig
   */
  protected ResultTypeConfig(ResultTypeConfig orig) {
   this.name = orig.name;
   this.className = orig.className;
   this.defaultResultParam = orig.defaultResultParam;
   this.params = orig.params;
  }

  /**
   * 设置默认的结果参数
   * @param defaultResultParam
   */
  public void setDefaultResultParam(String defaultResultParam) {
   this.defaultResultParam = defaultResultParam;
  }
  
  /**
   * 获取默认的结果参数
   * @return
   */
  public String getDefaultResultParam() {
   return this.defaultResultParam;
  }

  /**
   * @deprecated Since 2.1, use {@link #getClassName()} instead
   */
  @Deprecated public String getClazz() {
   return className;
  }

  public String getClassName() {
   return className;
  }

  public String getName() {
   return name;
  }

  public Map<String,String> getParams() {
   return this.params;
  }

  @Override
  public boolean equals(Object o) {
   if (this == o) return true;
   if (o == null || getClass() != o.getClass()) return false;

   final ResultTypeConfig that = (ResultTypeConfig) o;

   if (className != null ? !className.equals(that.className) : that.className != null) return false;
   if (name != null ? !name.equals(that.name) : that.name != null) return false;
   if (params != null ? !params.equals(that.params) : that.params != null) return false;

   return true;
  }

  @Override
  public int hashCode() {
   int result;
   result = (className != null ? className.hashCode() : 0);
   result = 29 * result + (name != null ? name.hashCode() : 0);
   result = 29 * result + (params != null ? params.hashCode() : 0);
   return result;
  }

  /**
   * 这个类的builder方法。唯一创建该类的实例的方法。目的是为了维持执行对象的不变性。
   * 该方式是通过结构化的方式来至此chain方式。设置完需要的参数之后,可以调用build方法创建一个实例
   * 一下内部类的方法,通过名称即可了解该方法的具体作用
   */
  public static final class Builder {
   protected ResultTypeConfig target;

   public Builder(String name, String className) {
    target = new ResultTypeConfig(name, className);
   }

   public Builder(ResultTypeConfig orig) {
    target = new ResultTypeConfig(orig);
   }

   public Builder name(String name) {
    target.name = name;
    return this;
   }

   public Builder className(String name) {
    target.className = name;
    return this;
   }

    public Builder addParam(String name, String value) {
    target.params.put(name, value);
    return this;
   }

   public Builder addParams(Map<String,String> params) {
    target.params.putAll(params);
    return this;
   }

   public Builder defaultResultParam(String defaultResultParam) {
    target.defaultResultParam = defaultResultParam;
    return this;
   }

   public Builder location(Location loc) {
    target.location = loc;
    return this;
   }

   public ResultTypeConfig build() {
    embalmTarget();
    ResultTypeConfig result = target;
    target = new ResultTypeConfig(target);
    return result;
   }

   protected void embalmTarget() {
    target.params = Collections.unmodifiableMap(target.params);
   }
  }
 }

 ActionConfig(com.opensymphony.xwork2.config.entities)

 /**
  * 包括所有需要被配置和一个可执行的action
  * <ul>
  * <li>方法名 - 这个方法名是将要被执行的action的方法。如果为空,这个Action将被关联到Action Interface并且执行execute()方法</li>
  * <li>类 - 这个Action的类名</li>
  * <li>参数 - 这些参数将被在action执行之前设置</li>
  * <li>结果 - 结果集 {String -> View class}</li>
  * <li>结果参数 - 返回结果的参数{String -> Map}</li>
  * <li>类型转换 - 用OGNL的类型转换为了使用getting/setting参数时</li>
  * </ul>
  */
 public class ActionConfig extends Located implements Serializable {

  public static final String DEFAULT_METHOD = "execute";//默认执行的方法名
  public static final String WILDCARD = "*";//通配符

  protected List<InterceptorMapping> interceptors; // 一个InterceptorMapping的列表对象
  protected Map<String,String> params;//参数
  protected Map<String, ResultConfig> results;//结果集
  protected List<ExceptionMappingConfig> exceptionMappings;//异常映射配置
  protected String className;//类名
  protected String methodName;//方法名
  protected String packageName;//包名
  protected String name;//名称
  protected Set<String> allowedMethods;

  /**
   * 构造方法
   * @param packageName
   * @param name
   * @param className
   */
  protected ActionConfig(String packageName, String name, String className) {
   this.packageName = packageName;
   this.name = name;
   this.className = className;
   params = new LinkedHashMap<String, String>();
   results = new LinkedHashMap<String, ResultConfig>();
   interceptors = new ArrayList<InterceptorMapping>();
   exceptionMappings = new ArrayList<ExceptionMappingConfig>();
   allowedMethods = new HashSet<String>();
  }

  /**
   * 负责一个ActionConfig对象
   * @param orig The ActionConfig to clone
   * @Since 2.1
   */
  protected ActionConfig(ActionConfig orig) {
   this.name = orig.name;
   this.className = orig.className;
   this.methodName = orig.methodName;
   this.packageName = orig.packageName;
   this.params = new LinkedHashMap<String,String>(orig.params);
   this.interceptors = new ArrayList<InterceptorMapping>(orig.interceptors);
   this.results = new LinkedHashMap<String,ResultConfig>(orig.results);
   this.exceptionMappings = new ArrayList<ExceptionMappingConfig>(orig.exceptionMappings);
   this.allowedMethods = new HashSet<String>(orig.allowedMethods);
  }

  public String getName() {
   return name;
  }

  public String getClassName() {
   return className;
  }

  public List<ExceptionMappingConfig> getExceptionMappings() {
   return exceptionMappings;
  }

  public List<InterceptorMapping> getInterceptors() {
   return interceptors;
  }

  public Set<String> getAllowedMethods() {
   return allowedMethods;
  }

  /**
   * 返回类中方法的名字
   *
   * @return name of the method to execute
   */
  public String getMethodName() {
   return methodName;
  }

  /**
   * @return Returns the packageName.
   */
  public String getPackageName() {
   return packageName;
  }

  public Map<String, String> getParams() {
   return params;
  }

  public Map<String, ResultConfig> getResults() {
   return results;
  }

  public boolean isAllowedMethod(String method) {
   if (allowedMethods.size() == 1 && WILDCARD.equals(allowedMethods.iterator().next())) {
    return true;
   } else {
    return method.equals(methodName != null ? methodName : DEFAULT_METHOD) || allowedMethods.contains(method);
   }
  }

  @Override public boolean equals(Object o) {
   if (this == o) {
    return true;
   }

   if (!(o instanceof ActionConfig)) {
    return false;
   }

   final ActionConfig actionConfig = (ActionConfig) o;

   if ((className != null) ? (!className.equals(actionConfig.className)) : (actionConfig.className != null)) {
    return false;
   }

   if ((name != null) ? (!name.equals(actionConfig.name)) : (actionConfig.name != null)) {
    return false;
   }

   if ((interceptors != null) ? (!interceptors.equals(actionConfig.interceptors)) : (actionConfig.interceptors != null))
   {
    return false;
   }

   if ((methodName != null) ? (!methodName.equals(actionConfig.methodName)) : (actionConfig.methodName != null)) {
    return false;
   }

   if ((params != null) ? (!params.equals(actionConfig.params)) : (actionConfig.params != null)) {
    return false;
   }

   if ((results != null) ? (!results.equals(actionConfig.results)) : (actionConfig.results != null)) {
    return false;
   }

   if ((allowedMethods != null) ? (!allowedMethods.equals(actionConfig.allowedMethods)) : (actionConfig.allowedMethods != null)) {
    return false;
   }

   return true;
  }

  @Override public int hashCode() {
   int result;
   result = (interceptors != null ? interceptors.hashCode() : 0);
   result = 31 * result + (params != null ? params.hashCode() : 0);
   result = 31 * result + (results != null ? results.hashCode() : 0);
   result = 31 * result + (exceptionMappings != null ? exceptionMappings.hashCode() : 0);
   result = 31 * result + (className != null ? className.hashCode() : 0);
   result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
   result = 31 * result + (packageName != null ? packageName.hashCode() : 0);
   result = 31 * result + (name != null ? name.hashCode() : 0);
   result = 31 * result + (allowedMethods != null ? allowedMethods.hashCode() : 0);
   return result;
  }

  @Override public String toString() {
   StringBuilder sb = new StringBuilder();
   sb.append("{ActionConfig ");
   sb.append(name).append(" (");
   sb.append(className);
   if (methodName != null) {
    sb.append(".").append(methodName).append("()");
   }
   sb.append(")");
   sb.append(" - ").append(location);
   sb.append("}");
   return sb.toString();
  }

  /**
   * 这个类的builder方法。唯一创建该类的实例的方法。目的是为了维持执行对象的不变性。
   * 该方式是通过结构化的方式来至此chain方式。设置完需要的参数之后,可以调用build方法创建一个实例
   */
  public static class Builder implements InterceptorListHolder{

   protected ActionConfig target;
   private boolean gotMethods;

   public Builder(ActionConfig toClone) {
    target = new ActionConfig(toClone);
    addAllowedMethod(toClone.getAllowedMethods());
   }

   public Builder(String packageName, String name, String className) {
    target = new ActionConfig(packageName, name, className);
   }

   public Builder packageName(String name) {
    target.packageName = name;
    return this;
   }

   public Builder name(String name) {
    target.name = name;
    return this;
   }

   public Builder className(String name) {
    target.className = name;
    return this;
   }

   public Builder defaultClassName(String name) {
    if (StringUtils.isEmpty(target.className)) {
     target.className = name;
    }
    return this;
   }

   public Builder methodName(String method) {
    target.methodName = method;
    return this;
   }

   public Builder addExceptionMapping(ExceptionMappingConfig exceptionMapping) {
    target.exceptionMappings.add(exceptionMapping);
    return this;
   }

   public Builder addExceptionMappings(Collection<? extends ExceptionMappingConfig> mappings) {
    target.exceptionMappings.addAll(mappings);
    return this;
   }

   public Builder exceptionMappings(Collection<? extends ExceptionMappingConfig> mappings) {
    target.exceptionMappings.clear();
    target.exceptionMappings.addAll(mappings);
    return this;
   }

   public Builder addInterceptor(InterceptorMapping interceptor) {
    target.interceptors.add(interceptor);
    return this;
   }

   public Builder addInterceptors(List<InterceptorMapping> interceptors) {
    target.interceptors.addAll(interceptors);
    return this;
   }

   public Builder interceptors(List<InterceptorMapping> interceptors) {
    target.interceptors.clear();
    target.interceptors.addAll(interceptors);
    return this;
   }

   public Builder addParam(String name, String value) {
    target.params.put(name, value);
    return this;
   }

   public Builder addParams(Map<String,String> params) {
    target.params.putAll(params);
    return this;
   }

   public Builder addResultConfig(ResultConfig resultConfig) {
    target.results.put(resultConfig.getName(), resultConfig);
    return this;
   }

   public Builder addResultConfigs(Collection<ResultConfig> configs) {
    for (ResultConfig rc : configs) {
     target.results.put(rc.getName(), rc);
    }
    return this;
   }

   public Builder addResultConfigs(Map<String,ResultConfig> configs) {
    target.results.putAll(configs);
    return this;
   }

   public Builder addAllowedMethod(String methodName) {
    target.allowedMethods.add(methodName);
    return this;
   }

   public Builder addAllowedMethod(Collection<String> methods) {
    if (methods != null) {
     gotMethods = true;
     target.allowedMethods.addAll(methods);
    }
    return this;
   }

   public Builder location(Location loc) {
    target.location = loc;
    return this;
   }

   public ActionConfig build() {
    embalmTarget();
    ActionConfig result = target;
    target = new ActionConfig(target);
    return result;
   }

   protected void embalmTarget() {
    if (!gotMethods && target.allowedMethods.isEmpty()) {
     target.allowedMethods.add(WILDCARD);
    }

    target.params = Collections.unmodifiableMap(target.params);
    target.results = Collections.unmodifiableMap(target.results);
    target.interceptors = Collections.unmodifiableList(target.interceptors);
    target.exceptionMappings = Collections.unmodifiableList(target.exceptionMappings);
    target.allowedMethods = Collections.unmodifiableSet(target.allowedMethods);
   }
  }
 }

  PackageConfig(com.opensymphony.xwork2.config.entities)

 /**
  * package的配置,在xml配置文件中,对应package标签
  */
 public class PackageConfig extends Located implements Comparable, Serializable, InterceptorLocator {

  private static final Logger LOG = LoggerFactory.getLogger(PackageConfig.class);

  protected Map<String, ActionConfig> actionConfigs;//定义一个ActionConfig的Map列表(相当于xml配置文件中的action)
  protected Map<String, ResultConfig> globalResultConfigs;//定义全局结果映射配置
  protected Map<String, Object> interceptorConfigs;//定义拦截器名字和类的映射关系
  protected Map<String, ResultTypeConfig> resultTypeConfigs;//返回类型的配置
  protected List<ExceptionMappingConfig> globalExceptionMappingConfigs;//全集异常映射配置
  protected List<PackageConfig> parents;//父package
  protected String defaultInterceptorRef;//默认拦截器
  protected String defaultActionRef;//默认Action-ref
  protected String defaultResultType;//默认返回结果类型
  protected String defaultClassRef;
  protected String name;//package名称
  protected String namespace = "";//namespace
  protected boolean isAbstract = false;
  protected boolean needsRefresh;

  /**
   * 初始化所有参数
   * @param name
   */
  protected PackageConfig(String name) {
   this.name = name;
   actionConfigs = new LinkedHashMap<String, ActionConfig>();
   globalResultConfigs = new LinkedHashMap<String, ResultConfig>();
   interceptorConfigs = new LinkedHashMap<String, Object>();
   resultTypeConfigs = new LinkedHashMap<String, ResultTypeConfig>();
   globalExceptionMappingConfigs = new ArrayList<ExceptionMappingConfig>();
   parents = new ArrayList<PackageConfig>();
  }

  /**
   * 通过现有的PackageConfig初始化所有的参数信息
   * @param orig
   */
  protected PackageConfig(PackageConfig orig) {
   this.defaultInterceptorRef = orig.defaultInterceptorRef;
   this.defaultActionRef = orig.defaultActionRef;
   this.defaultResultType = orig.defaultResultType;
   this.defaultClassRef = orig.defaultClassRef;
   this.name = orig.name;
   this.namespace = orig.namespace;
   this.isAbstract = orig.isAbstract;
   this.needsRefresh = orig.needsRefresh;
   this.actionConfigs = new LinkedHashMap<String, ActionConfig>(orig.actionConfigs);
   this.globalResultConfigs = new LinkedHashMap<String, ResultConfig>(orig.globalResultConfigs);
   this.interceptorConfigs = new LinkedHashMap<String, Object>(orig.interceptorConfigs);
   this.resultTypeConfigs = new LinkedHashMap<String, ResultTypeConfig>(orig.resultTypeConfigs);
   this.globalExceptionMappingConfigs = new ArrayList<ExceptionMappingConfig>(orig.globalExceptionMappingConfigs);
   this.parents = new ArrayList<PackageConfig>(orig.parents);
  }

  /**
   * 返回是否是抽象的
   * @return
   */
  public boolean isAbstract() {
   return isAbstract;
  }

  /**
   * 返回actionConfigs
   * @return
   */
  public Map<String, ActionConfig> getActionConfigs() {
   return actionConfigs;
  }

  /**
   * 返回当前package中所有可用的ActionConfigs映射,在父类packages中定义的ActionConfigs将被包含在这个Map里面
   * @return 一个以action作为名词的ActionConfig对象的Map
   * @see ActionConfig
   */
  public Map<String, ActionConfig> getAllActionConfigs() {
   Map<String, ActionConfig> retMap = new LinkedHashMap<String, ActionConfig>();

   if (!parents.isEmpty()) {
    for (PackageConfig parent : parents) {
     retMap.putAll(parent.getAllActionConfigs());
    }
   }

   retMap.putAll(getActionConfigs());

   return retMap;
  }

  /**
   * returns the Map of all the global ResultConfigs available in the current package.
   * Global ResultConfigs defined in ancestor packages will be included in this Map.
   *
   * @return a Map of Result Objects with the result name as the key
   * @see ResultConfig
   */
  public Map<String, ResultConfig> getAllGlobalResults() {
   Map<String, ResultConfig> retMap = new LinkedHashMap<String, ResultConfig>();

   if (!parents.isEmpty()) {
    for (PackageConfig parentConfig : parents) {
     retMap.putAll(parentConfig.getAllGlobalResults());
    }
   }

   retMap.putAll(getGlobalResultConfigs());

   return retMap;
  }

  /**
   * returns the Map of all InterceptorConfigs and InterceptorStackConfigs available in the current package.
   * InterceptorConfigs defined in ancestor packages will be included in this Map.
   *
   * @return a Map of InterceptorConfig and InterceptorStackConfig Objects with the ref-name as the key
   * @see InterceptorConfig
   * @see InterceptorStackConfig
   */
  public Map<String, Object> getAllInterceptorConfigs() {
   Map<String, Object> retMap = new LinkedHashMap<String, Object>();

   if (!parents.isEmpty()) {
    for (PackageConfig parentContext : parents) {
     retMap.putAll(parentContext.getAllInterceptorConfigs());
    }
   }

   retMap.putAll(getInterceptorConfigs());

   return retMap;
  }

  /**
   * returns the Map of all the ResultTypeConfigs available in the current package.
   * ResultTypeConfigs defined in ancestor packages will be included in this Map.
   *
   * @return a Map of ResultTypeConfig Objects with the result type name as the key
   * @see ResultTypeConfig
   */
  public Map<String, ResultTypeConfig> getAllResultTypeConfigs() {
   Map<String, ResultTypeConfig> retMap = new LinkedHashMap<String, ResultTypeConfig>();

   if (!parents.isEmpty()) {
    for (PackageConfig parentContext : parents) {
     retMap.putAll(parentContext.getAllResultTypeConfigs());
    }
   }

   retMap.putAll(getResultTypeConfigs());

   return retMap;
  }

  /**
   * returns the List of all the ExceptionMappingConfigs available in the current package.
   * ExceptionMappingConfigs defined in ancestor packages will be included in this list.
   *
   * @return a List of ExceptionMappingConfigs Objects with the result type name as the key
   * @see ExceptionMappingConfig
   */
  public List<ExceptionMappingConfig> getAllExceptionMappingConfigs() {
   List<ExceptionMappingConfig> allExceptionMappings = new ArrayList<ExceptionMappingConfig>();

   if (!parents.isEmpty()) {
    for (PackageConfig parentContext : parents) {
     allExceptionMappings.addAll(parentContext.getAllExceptionMappingConfigs());
    }
   }

   allExceptionMappings.addAll(getGlobalExceptionMappingConfigs());

   return allExceptionMappings;
  }


  public String getDefaultInterceptorRef() {
   return defaultInterceptorRef;
  }

  public String getDefaultActionRef() {
   return defaultActionRef;
  }

  public String getDefaultClassRef() {
   if ((defaultClassRef == null) && !parents.isEmpty()) {
    for (PackageConfig parent : parents) {
     String parentDefault = parent.getDefaultClassRef();
     if (parentDefault != null) {
      return parentDefault;
     }
    }
   }
   return defaultClassRef;
  }

  /**
   * Returns the default result type for this package.
   */
  public String getDefaultResultType() {
   return defaultResultType;
  }

  /**
   * gets the default interceptor-ref name. If this is not set on this PackageConfig, it searches the parent
   * PackageConfigs in order until it finds one.
   */
  public String getFullDefaultInterceptorRef() {
   if ((defaultInterceptorRef == null) && !parents.isEmpty()) {
    for (PackageConfig parent : parents) {
     String parentDefault = parent.getFullDefaultInterceptorRef();

     if (parentDefault != null) {
      return parentDefault;
     }
    }
   }

   return defaultInterceptorRef;
  }

  /**
   * gets the default action-ref name. If this is not set on this PackageConfig, it searches the parent
   * PackageConfigs in order until it finds one.
   */
  public String getFullDefaultActionRef() {
   if ((defaultActionRef == null) && !parents.isEmpty()) {
    for (PackageConfig parent : parents) {
     String parentDefault = parent.getFullDefaultActionRef();

     if (parentDefault != null) {
      return parentDefault;
     }
    }
   }
   return defaultActionRef;
  }

  /**
   * 返回该package的默认的result type
   * 如果该package没有默认的result tyoe,但是它有父package,我们将尝试寻找该package的父package的默认result type
   */
  public String getFullDefaultResultType() {
   if ((defaultResultType == null) && !parents.isEmpty()) {
    for (PackageConfig parent : parents) {
     String parentDefault = parent.getFullDefaultResultType();

     if (parentDefault != null) {
      return parentDefault;
     }
    }
   }

   return defaultResultType;
  }

  /**
   * gets the global ResultConfigs local to this package
   *
   * @return a Map of ResultConfig objects keyed by result name
   * @see ResultConfig
   */
  public Map<String, ResultConfig> getGlobalResultConfigs() {
   return globalResultConfigs;
  }

  /**
   * gets the InterceptorConfigs and InterceptorStackConfigs local to this package
   *
   * @return a Map of InterceptorConfig and InterceptorStackConfig objects keyed by ref-name
   * @see InterceptorConfig
   * @see InterceptorStackConfig
   */
  public Map<String, Object> getInterceptorConfigs() {
   return interceptorConfigs;
  }

  public String getName() {
   return name;
  }

  public String getNamespace() {
   return namespace;
  }

  public List<PackageConfig> getParents() {
   return new ArrayList<PackageConfig>(parents);
  }

  /**
   * gets the ResultTypeConfigs local to this package
   *
   * @return a Map of ResultTypeConfig objects keyed by result name
   * @see ResultTypeConfig
   */
  public Map<String, ResultTypeConfig> getResultTypeConfigs() {
   return resultTypeConfigs;
  }


  public boolean isNeedsRefresh() {
   return needsRefresh;
  }

  /**
   * gets the ExceptionMappingConfigs local to this package
   *
   * @return a Map of ExceptionMappingConfig objects keyed by result name
   * @see ExceptionMappingConfig
   */
  public List<ExceptionMappingConfig> getGlobalExceptionMappingConfigs() {
   return globalExceptionMappingConfigs;
  }

  @Override
  public boolean equals(Object o) {
   if (this == o) {
    return true;
   }

   if (!(o instanceof PackageConfig)) {
    return false;
   }

   final PackageConfig packageConfig = (PackageConfig) o;

   if (isAbstract != packageConfig.isAbstract) {
    return false;
   }

   if ((actionConfigs != null) ? (!actionConfigs.equals(packageConfig.actionConfigs)) : (packageConfig.actionConfigs != null)) {
    return false;
   }

   if ((defaultResultType != null) ? (!defaultResultType.equals(packageConfig.defaultResultType)) : (packageConfig.defaultResultType != null)) {
    return false;
   }

   if ((defaultClassRef != null) ? (!defaultClassRef.equals(packageConfig.defaultClassRef)) : (packageConfig.defaultClassRef != null)) {
    return false;
   }

   if ((globalResultConfigs != null) ? (!globalResultConfigs.equals(packageConfig.globalResultConfigs)) : (packageConfig.globalResultConfigs != null)) {
    return false;
   }

   if ((interceptorConfigs != null) ? (!interceptorConfigs.equals(packageConfig.interceptorConfigs)) : (packageConfig.interceptorConfigs != null)) {
    return false;
   }

   if ((name != null) ? (!name.equals(packageConfig.name)) : (packageConfig.name != null)) {
    return false;
   }

   if ((namespace != null) ? (!namespace.equals(packageConfig.namespace)) : (packageConfig.namespace != null)) {
    return false;
   }

   if ((parents != null) ? (!parents.equals(packageConfig.parents)) : (packageConfig.parents != null)) {
    return false;
   }

   if ((resultTypeConfigs != null) ? (!resultTypeConfigs.equals(packageConfig.resultTypeConfigs)) : (packageConfig.resultTypeConfigs != null)) {
    return false;
   }

   if ((globalExceptionMappingConfigs != null) ? (!globalExceptionMappingConfigs.equals(packageConfig.globalExceptionMappingConfigs)) : (packageConfig.globalExceptionMappingConfigs != null)) {
    return false;
   }

   return true;
  }

  @Override
  public int hashCode() {
   int result;
   result = ((name != null) ? name.hashCode() : 0);
   result = (29 * result) + ((parents != null) ? parents.hashCode() : 0);
   result = (29 * result) + ((actionConfigs != null) ? actionConfigs.hashCode() : 0);
   result = (29 * result) + ((globalResultConfigs != null) ? globalResultConfigs.hashCode() : 0);
   result = (29 * result) + ((interceptorConfigs != null) ? interceptorConfigs.hashCode() : 0);
   result = (29 * result) + ((resultTypeConfigs != null) ? resultTypeConfigs.hashCode() : 0);
   result = (29 * result) + ((globalExceptionMappingConfigs != null) ? globalExceptionMappingConfigs.hashCode() : 0);
   result = (29 * result) + ((defaultResultType != null) ? defaultResultType.hashCode() : 0);
   result = (29 * result) + ((defaultClassRef != null) ? defaultClassRef.hashCode() : 0);
   result = (29 * result) + ((namespace != null) ? namespace.hashCode() : 0);
   result = (29 * result) + (isAbstract ? 1 : 0);

   return result;
  }

  @Override
  public String toString() {
   return "{PackageConfig Name:" + name + " namespace:" + namespace + " parents:" + parents + "}";
  }

  public int compareTo(Object o) {
   PackageConfig other = (PackageConfig) o;
   String full = namespace + "!" + name;
   String otherFull = other.namespace + "!" + other.name;

   // note, this isn't perfect (could come from different parents), but it is "good enough"
   return full.compareTo(otherFull);
  }

  public Object getInterceptorConfig(String name) {
   return getAllInterceptorConfigs().get(name);
  }

  /**
   * 这个类的构建类。该实例是唯一创建该对象实例的方法。目的是执行对象的不变性。这个方法将被用来支持链式创建。
   * 当设置完了你需要设置的参数之后,通过调用build()方法,就可以常见该对象
   */
  public static class Builder implements InterceptorLocator {

   //该对象的一个实例
   protected PackageConfig target;
   private boolean strictDMI;
   /**
    * 设置package的名称
    * @param name 
    */
   public Builder(String name) {
    target = new PackageConfig(name);
   }
   
   /**
    * 通过复制config创建一个新的PackageConfig对象
    * @param config
    */
   public Builder(PackageConfig config) {
    target = new PackageConfig(config);
   }

   /**
    * 设置target对象的名称
    * @param name
    * @return
    */
   public Builder name(String name) {
    target.name = name;
    return this;
   }
   
   /**
    * 设置target对象的isabstract属性
    * @param isAbstract
    * @return
    */
   public Builder isAbstract(boolean isAbstract) {
    target.isAbstract = isAbstract;
    return this;
   }
   
   /**
    * 设置对象的defaultInterceptorRef属性
    * @param name
    * @return
    */
   public Builder defaultInterceptorRef(String name) {
    target.defaultInterceptorRef = name;
    return this;
   }

   /**
    * 设置对象的defaultActionRef属性
    * @param name
    * @return
    */
   public Builder defaultActionRef(String name) {
    target.defaultActionRef = name;
    return this;
   }

   /**
    * 设置对象的defaultClassRef属性
    * @param defaultClassRef
    * @return
    */
   public Builder defaultClassRef(String defaultClassRef) {
    target.defaultClassRef = defaultClassRef;
    return this;
   }

   /**
    * 为这个Package设置默认的结果类型
    * 
    * @param defaultResultType
    */
   public Builder defaultResultType(String defaultResultType) {
    target.defaultResultType = defaultResultType;
    return this;
   }
   
   /**
    * 为当前target设置namespace属性
    * @param namespace
    * @return
    */
   public Builder namespace(String namespace) {
    if (namespace == null) {
     target.namespace = "";
    } else {
     target.namespace = namespace;
    }
    return this;
   }

   public Builder needsRefresh(boolean needsRefresh) {
    target.needsRefresh = needsRefresh;
    return this;
   }

   public Builder addActionConfig(String name, ActionConfig action) {
    target.actionConfigs.put(name, action);
    return this;
   }

   public Builder addParents(List<PackageConfig> parents) {
    for (PackageConfig config : parents) {
     addParent(config);
    }
    return this;
   }

   public Builder addGlobalResultConfig(ResultConfig resultConfig) {
    target.globalResultConfigs.put(resultConfig.getName(), resultConfig);
    return this;
   }

   public Builder addGlobalResultConfigs(Map<String, ResultConfig> resultConfigs) {
    target.globalResultConfigs.putAll(resultConfigs);
    return this;
   }

   public Builder addExceptionMappingConfig(ExceptionMappingConfig exceptionMappingConfig) {
    target.globalExceptionMappingConfigs.add(exceptionMappingConfig);
    return this;
   }

   public Builder addGlobalExceptionMappingConfigs(List<ExceptionMappingConfig> exceptionMappingConfigs) {
    target.globalExceptionMappingConfigs.addAll(exceptionMappingConfigs);
    return this;
   }

   public Builder addInterceptorConfig(InterceptorConfig config) {
    target.interceptorConfigs.put(config.getName(), config);
    return this;
   }

   public Builder addInterceptorStackConfig(InterceptorStackConfig config) {
    target.interceptorConfigs.put(config.getName(), config);
    return this;
   }

   public Builder addParent(PackageConfig parent) {
    target.parents.add(0, parent);
    return this;
   }

   public Builder addResultTypeConfig(ResultTypeConfig config) {
    target.resultTypeConfigs.put(config.getName(), config);
    return this;
   }

   public Builder location(Location loc) {
    target.location = loc;
    return this;
   }

   public boolean isNeedsRefresh() {
    return target.needsRefresh;
   }

   public String getDefaultClassRef() {
    return target.defaultClassRef;
   }

   public String getName() {
    return target.name;
   }

   public String getNamespace() {
    return target.namespace;
   }

   /**
    * 返回该package的默认的result type
    * @return
    */
   public String getFullDefaultResultType() {
    return target.getFullDefaultResultType();
   }

   public ResultTypeConfig getResultType(String type) {
    return target.getAllResultTypeConfigs().get(type);
   }

   public Object getInterceptorConfig(String name) {
    return target.getAllInterceptorConfigs().get(name);
   }

   public Builder strictMethodInvocation(boolean strict) {
    strictDMI = strict;
    return this;
   }

   public boolean isStrictMethodInvocation() {
    return strictDMI;
   }

   public PackageConfig build() {
    embalmTarget();
    PackageConfig result = target;
    target = new PackageConfig(result);
    return result;
   }

   protected void embalmTarget() {
    target.actionConfigs = Collections.unmodifiableMap(target.actionConfigs);
    target.globalResultConfigs = Collections.unmodifiableMap(target.globalResultConfigs);
    target.interceptorConfigs = Collections.unmodifiableMap(target.interceptorConfigs);
    target.resultTypeConfigs = Collections.unmodifiableMap(target.resultTypeConfigs);
    target.globalExceptionMappingConfigs = Collections.unmodifiableList(target.globalExceptionMappingConfigs);
    target.parents = Collections.unmodifiableList(target.parents);
   }

   @Override
   public String toString() {
    return "[BUILDER] " + target.toString();
   }
  }

 }

  这个方法中所需的类基本介绍完了,下面介绍解析过程;在此调用XmlConfigurationProvider类的addPackage(Element packageElement)方法,该方法具体内容如下:

  /**
     * 创建一个XML元素代表一个packageconfig。
     */
    protected PackageConfig addPackage(Element packageElement) throws ConfigurationException {
        //创建一个PackageConfig的内部类Builder
     PackageConfig.Builder newPackage = buildPackageContext(packageElement);//用该类创建一个package对象

        if (newPackage.isNeedsRefresh()) {
            return newPackage.build();
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Loaded " + newPackage);
        }

        //为这个package添加result types 和默认的result
        addResultTypes(newPackage, packageElement);

        //为这个package添加interceptors和interceptor stacks
        loadInterceptors(newPackage, packageElement);

        //为这个package添加默认的interceptors
        loadDefaultInterceptorRef(newPackage, packageElement);

        //为这个package添加默认的default-class-ref
        loadDefaultClassRef(newPackage, packageElement);

        //为package添加全局results
        loadGlobalResults(newPackage, packageElement);

        //为这个package添加全局的exception
        loadGobalExceptionMappings(newPackage, packageElement);

        //获取action元素
        NodeList actionList = packageElement.getElementsByTagName("action");

        //遍历action元素
        for (int i = 0; i < actionList.getLength(); i++) {
            Element actionElement = (Element) actionList.item(i);//获取第i个action元素
            //把该action元素添加到package中
            addAction(actionElement, newPackage);
        }

        // load the default action reference for this package
        //为该package加载默认的action
        loadDefaultActionRef(newPackage, packageElement);
        //实例化一个PackageConfig对象
        PackageConfig cfg = newPackage.build();
        //把该对象添加到configuration(DefaultConfiguration)的packageContexts中
        configuration.addPackageConfig(cfg.getName(), cfg);
        //返回该cfg对象
        return cfg;
    }

在这里对其具体代码进行分析:

//为这个package添加result types 和默认的result
  addResultTypes(newPackage, packageElement);该方法的具体代码如下:

/**
     * 为这个package添加result types 和默认的result
     * @param packageContext
     * @param element
     */
    protected void addResultTypes(PackageConfig.Builder packageContext, Element element) {
        NodeList resultTypeList = element.getElementsByTagName("result-type");//以getElementsByTagName的形式获取所有的("result-type")
        /**
         * 对result-type进行遍历
         */
        for (int i = 0; i < resultTypeList.getLength(); i++) {
            Element resultTypeElement = (Element) resultTypeList.item(i);//获取第I个node对象
            String name = resultTypeElement.getAttribute("name");//获取该元素的name属性
            String className = resultTypeElement.getAttribute("class");//获取该元素的class属性
            String def = resultTypeElement.getAttribute("default");//获取该元素的defaul属性

            /**
             * 获取该元素的location
             */
            Location loc = DomHelper.getLocationObject(resultTypeElement);
            //获取指定类名的类
            Class clazz = verifyResultType(className, loc);
            if (clazz != null) {
                String paramName = null;
                try {
                    paramName = (String) clazz.getField("DEFAULT_PARAM").get(null);
                }
                catch (Throwable t) {
                    // if we get here, the result type doesn't have a default param defined.
                }
                /**
                 * 创建一个ResultTypeConfig对象
                 */
                ResultTypeConfig.Builder resultType = new ResultTypeConfig.Builder(name, className).defaultResultParam(paramName)
                        .location(DomHelper.getLocationObject(resultTypeElement));

                Map<String, String> params = XmlHelper.getParams(resultTypeElement);

                if (!params.isEmpty()) {
                    resultType.addParams(params);
                }
                packageContext.addResultTypeConfig(resultType.build());

                // 设置默认的结果类型
                if ("true".equals(def)) {
                    packageContext.defaultResultType(name);
                }
            }
        }
    }

//为这个package添加interceptors和interceptor stacks
  loadInterceptors(newPackage, packageElement);该方法具体内容如下:

/**
     * 为这个package添加interceptors和interceptor stacks
     * @param context
     * @param element
     * @throws ConfigurationException
     */
    protected void loadInterceptors(PackageConfig.Builder context, Element element) throws ConfigurationException {
        NodeList interceptorList = element.getElementsByTagName("interceptor");//获取所有的interceptor配置
        //对获取到的interceptor列表进行遍历
        for (int i = 0; i < interceptorList.getLength(); i++) {
            Element interceptorElement = (Element) interceptorList.item(i);//获取第i个元素
            String name = interceptorElement.getAttribute("name");//获取元素的name
            String className = interceptorElement.getAttribute("class");//获取元素的class

            Map<String, String> params = XmlHelper.getParams(interceptorElement);
            /**
             * 创建一个InterceptorConfig对象
             */
            InterceptorConfig config = new InterceptorConfig.Builder(name, className)
                    .addParams(params)
                    .location(DomHelper.getLocationObject(interceptorElement))
                    .build();

            //把创建的InterceptorConfig对象放入PackageConfig中
            context.addInterceptorConfig(config);
        }

        /**
         * 加载InterceptorStack
         */
        loadInterceptorStacks(element, context);
    }

 在该方法中又调用了设置InterceptorStacks的方法,该方法具体如下:

 /**
     * 为package加载InterceptorStack
     * @param element
     * @param context
     * @throws ConfigurationException
     */
    protected void loadInterceptorStacks(Element element, PackageConfig.Builder context) throws ConfigurationException {
        NodeList interceptorStackList = element.getElementsByTagName("interceptor-stack");//获取名字为interceptor-stack的节点

        /**
         * 对节点进行遍历
         */
        for (int i = 0; i < interceptorStackList.getLength(); i++) {
            Element interceptorStackElement = (Element) interceptorStackList.item(i);//获取第I个节点
            
            InterceptorStackConfig config = loadInterceptorStack(interceptorStackElement, context);

            context.addInterceptorStackConfig(config);
        }
    }

 在该方法内部调用了loadInterceptorStack方法,该方法具体如下:

/**
     * 加载InterceptorStack
     */
    protected InterceptorStackConfig loadInterceptorStack(Element element, PackageConfig.Builder context) throws ConfigurationException {
        String name = element.getAttribute("name");//得到节点的名字

        InterceptorStackConfig.Builder config = new InterceptorStackConfig.Builder(name)
                .location(DomHelper.getLocationObject(element));//创建一个InterceptorStackConfig对象
        NodeList interceptorRefList = element.getElementsByTagName("interceptor-ref");//查找所有的interceptor-ref的节点

        /**
         * 对查找到的Node进行遍历
         */
        for (int j = 0; j < interceptorRefList.getLength(); j++) {
            Element interceptorRefElement = (Element) interceptorRefList.item(j);//获取第J个节点
            List<InterceptorMapping> interceptors = lookupInterceptorReference(context, interceptorRefElement);
            config.addInterceptors(interceptors);
        }

        return config.build();
    } 

 在该方法内部调用lookupInterceptorReference方法,该方法具体内容如下:

 /**
     * 从interceptor-ref的名字查找Interceptor类并创建一个实例,并添加到provided List中,或,
     * 如果这个ref是一个stack,它将会把这个Interceptor实例从List中添加到一个stack中
     * @param interceptorRefElement Element to pull interceptor ref data from
     * @param context               The PackageConfig to lookup the interceptor from
     * @return A list of Interceptor objects
     */
    private List<InterceptorMapping> lookupInterceptorReference(PackageConfig.Builder context, Element interceptorRefElement) throws ConfigurationException {
        String refName = interceptorRefElement.getAttribute("name");//获取节点的名称
        Map<String, String> refParams = XmlHelper.getParams(interceptorRefElement);

        Location loc = LocationUtils.getLocation(interceptorRefElement);
        return InterceptorBuilder.constructInterceptorReference(context, refName, refParams, loc, objectFactory);
    }

  至此该package的InterceptorStack加载完成
  //为这个package添加默认的interceptors
  loadDefaultInterceptorRef(newPackage, packageElement);

 /**
     * 加载默认的defaul interceptor
     * @param packageContext
     * @param element
     */
    protected void loadDefaultInterceptorRef(PackageConfig.Builder packageContext, Element element) {
        NodeList resultTypeList = element.getElementsByTagName("default-interceptor-ref");//获取package下面的所有的default-interceptor-ref元素
        /**
         * 若default-interceptor-ref元素多于0个
         */
        if (resultTypeList.getLength() > 0) {
         //获取第一个default-interceptor节点
            Element defaultRefElement = (Element) resultTypeList.item(0);
            packageContext.defaultInterceptorRef(defaultRefElement.getAttribute("name"));//把default-interceptor-ref的名字添加到package中
        }
    }

  //为这个package添加默认的default-class-ref
  loadDefaultClassRef(newPackage, packageElement);

   /**
     * 加载默认的default-class-ref标签
     * @param packageContext
     * @param element
     */
    protected void loadDefaultClassRef(PackageConfig.Builder packageContext, Element element) {
        NodeList defaultClassRefList = element.getElementsByTagName("default-class-ref");//获取所有的default-class-ref节点
        //如果在配置文件中节点名的节点大于0
        if (defaultClassRefList.getLength() > 0) {
            Element defaultClassRefElement = (Element) defaultClassRefList.item(0);//获取第一个节点
            packageContext.defaultClassRef(defaultClassRefElement.getAttribute("class"));//放入package的defaultClassRef中
        }
    }

  //为package添加全局results
  loadGlobalResults(newPackage, packageElement);

 /**
     * 为package添加全局results
     */
    protected void loadGlobalResults(PackageConfig.Builder packageContext, Element packageElement) {
        NodeList globalResultList = packageElement.getElementsByTagName("global-results");//查询所有的global-results

        //如果在配置文件中节点名的节点大于0
        if (globalResultList.getLength() > 0) {
            Element globalResultElement = (Element) globalResultList.item(0);//获取该节点的第0个节点
            Map<String, ResultConfig> results = buildResults(globalResultElement, packageContext);//创建一个全局result到包的映射关系
            packageContext.addGlobalResultConfigs(results);
        }
    }  

  //为这个package添加全局的exception
  loadGobalExceptionMappings(newPackage, packageElement);

/**
     * 从xml的元素中添加全局的结果Exception
     */
    protected void loadGobalExceptionMappings(PackageConfig.Builder packageContext, Element packageElement) {
        NodeList globalExceptionMappingList = packageElement.getElementsByTagName("global-exception-mappings");//查找所有的global-exception-mappings

        //如果节点中global-exception-mappings的个数大于0
        if (globalExceptionMappingList.getLength() > 0) {
            Element globalExceptionMappingElement = (Element) globalExceptionMappingList.item(0);//获取第一个global-exception-mapping节点
            List<ExceptionMappingConfig> exceptionMappings = buildExceptionMappings(globalExceptionMappingElement, packageContext);
            packageContext.addGlobalExceptionMappingConfigs(exceptionMappings);//为package添加全局异常映射关系
        }
    }
  

  NodeList actionList = packageElement.getElementsByTagName("action");//查找所有的action节点
  //把该action元素添加到package中
  addAction(actionElement, newPackage);

/**
     * 把Action放入package中
     * @param actionElement action节点
     * @param packageContext package上下文
     * @throws ConfigurationException 异常信息
     */
    protected void addAction(Element actionElement, PackageConfig.Builder packageContext) throws ConfigurationException {
        String name = actionElement.getAttribute("name");//获取action的名称
        String className = actionElement.getAttribute("class");//获取节点的class
        String methodName = actionElement.getAttribute("method");//获取节点的method
        Location location = DomHelper.getLocationObject(actionElement);//获取该节点的location
        //判断location是否为空
        if (location == null) {
            if (LOG.isWarnEnabled()) {
            LOG.warn("location null for " + className);
            }
        }
        //如果methodName为空,则设置其为null
        methodName = (methodName.trim().length() > 0) ? methodName.trim() : null;

        // if there isnt a class name specified for an <action/> then try to
        // use the default-class-ref from the <package/>
        //该部分代码已注释
        if (StringUtils.isEmpty(className)) {
            // if there is a package default-class-ref use that, otherwise use action support
           /* if (StringUtils.isNotEmpty(packageContext.getDefaultClassRef())) {
                className = packageContext.getDefaultClassRef();
            } else {
                className = ActionSupport.class.getName();
            }*/

        } else {
            if (!verifyAction(className, name, location)) {
                if (LOG.isErrorEnabled())
                    LOG.error("Unable to verify action [#0] with class [#1], from [#2]", name, className, location.toString());
                return;
            }
        }
        //配置result
        Map<String, ResultConfig> results;
        try {
         //创建一个ResultConfig对象的map从给定的xml元素
            results = buildResults(actionElement, packageContext);
        } catch (ConfigurationException e) {
            throw new ConfigurationException("Error building results for action " + name + " in namespace " + packageContext.getNamespace(), e, actionElement);
        }
        
        //获取该action的拦截器
        List<InterceptorMapping> interceptorList = buildInterceptorList(actionElement, packageContext);
        //获取该action的异常映射
        List<ExceptionMappingConfig> exceptionMappings = buildExceptionMappings(actionElement, packageContext);
        //获取该action的allowed-method属性集合
        Set<String> allowedMethods = buildAllowedMethods(actionElement, packageContext);
        //根据解析出来的数据创建一个ActionConfig对象
        ActionConfig actionConfig = new ActionConfig.Builder(packageContext.getName(), name, className)
                .methodName(methodName)
                .addResultConfigs(results)
                .addInterceptors(interceptorList)
                .addExceptionMappings(exceptionMappings)
                .addParams(XmlHelper.getParams(actionElement))
                .addAllowedMethod(allowedMethods)
                .location(location)
                .build();
        //把新建的actionconfig放入packageContext中
        packageContext.addActionConfig(name, actionConfig);

        if (LOG.isDebugEnabled()) {
            LOG.debug("Loaded " + (StringUtils.isNotEmpty(packageContext.getNamespace()) ? (packageContext.getNamespace() + "/") : "") + name + " in '" + packageContext.getName() + "' package:" + actionConfig);
        }
    }  

 在这个方法内部调用了buildResult(Element element, PackageConfig.Builder packageContext)方法,该方法具体如下:

 /**
     * 创建一个ResultConfig对象的map从给定的xml元素
     */
    protected Map<String, ResultConfig> buildResults(Element element, PackageConfig.Builder packageContext) {
        NodeList resultEls = element.getElementsByTagName("result");//获取节点的所有result节点

        Map<String, ResultConfig> results = new LinkedHashMap<String, ResultConfig>();//创建一个result的map

        /**
         * 遍历result节点
         */
        for (int i = 0; i < resultEls.getLength(); i++) {
            Element resultElement = (Element) resultEls.item(i);//获取第i个节点

            /**
             * 如果该节点的父节点为给定的global-results节点,或该节点的父节点的名字等于给定的global-results节点的名字相等
             */
            if (resultElement.getParentNode().equals(element) || resultElement.getParentNode().getNodeName().equals(element.getNodeName())) {
                String resultName = resultElement.getAttribute("name");//获取该节点的name属性
                String resultType = resultElement.getAttribute("type");//获取该节点的type属性

                //如果未设置该节点的name属性,则默认为SUCCESS
                if (StringUtils.isEmpty(resultName)) {
                    resultName = Action.SUCCESS;
                }

                //如果未设置该节点的type属性,我们将继承该节点的父package的类型
                if (StringUtils.isEmpty(resultType)) {
                 //得到该节点父节点的默认result type
                    resultType = packageContext.getFullDefaultResultType();

                    //监测当前的resulttype是否有值
                    if (StringUtils.isEmpty(resultType)) {
                        //如果没值,则抛出异常
                        throw new ConfigurationException("No result type specified for result named '"
                                + resultName + "', perhaps the parent package does not specify the result type?", resultElement);
                    }
                }


                /**
                 * 获取该package中的resultType
                 */
                ResultTypeConfig config = packageContext.getResultType(resultType);

                if (config == null) {
                    throw new ConfigurationException("There is no result type defined for type '" + resultType
                            + "' mapped with name '" + resultName + "'."
                            + "  Did you mean '" + guessResultType(resultType) + "'?", resultElement);
                }

                //获取ResultTypeConfig的类
                String resultClass = config.getClazz();

                //无效的结果类型定义的结果
                if (resultClass == null) {
                    throw new ConfigurationException("Result type '" + resultType + "' is invalid");
                }

                /**
                 * 获取该resultElement的一个resultParams的Map
                 */
                Map<String, String> resultParams = XmlHelper.getParams(resultElement);

                if (resultParams.size() == 0) //或许,这里之后一个默认的参数
                {
                 //如果<result ...>something</result>让后我们将添加一个'something'的 属性作为经常用到的属性
                    if (resultElement.getChildNodes().getLength() >= 1) {
                     //新建一个LinkedHashMap
                        resultParams = new LinkedHashMap<String, String>();

                        String paramName = config.getDefaultResultParam();//获取默认的result参数
                        //如果默认参数不为空
                        if (paramName != null) {
                            StringBuilder paramValue = new StringBuilder();//创建一个StringBuilder对象
                            //遍历resultElement的子节点
                            for (int j = 0; j < resultElement.getChildNodes().getLength(); j++) {
                             //如果该节点的节点类型是TEXT_NODE的话
                                if (resultElement.getChildNodes().item(j).getNodeType() == Node.TEXT_NODE) {
                                    String val = resultElement.getChildNodes().item(j).getNodeValue();//获取节点值
                                    //如果节点值不为空,则把其添加到paramValue中
                                    if (val != null) {
                                        paramValue.append(val);
                                    }
                                }
                            }
                            String val = paramValue.toString().trim();//去掉空格
                            //如果其不为空,则把结果放入resultParams中
                            if (val.length() > 0) {
                                resultParams.put(paramName, val);
                            }
                        } else {
                            if (LOG.isWarnEnabled()) {
                            LOG.warn("no default parameter defined for result of type " + config.getName());
                            }
                        }
                    }
                }

                //创建一个新的参数map,如此一来,这些结果参数能覆盖配置参数
                Map<String, String> params = new LinkedHashMap<String, String>();
                Map<String, String> configParams = config.getParams();//获取ResultTypeConfig中的配置参数
                //如果配置参数不为空,则把其放入新建立的params的MAP中
                if (configParams != null) {
                    params.putAll(configParams);
                }
                //把resultParams放入params中
                params.putAll(resultParams);

                /**
                 * 创建一个新的resultConfig
                 */
                ResultConfig resultConfig = new ResultConfig.Builder(resultName, resultClass)
                        .addParams(params)
                        .location(DomHelper.getLocationObject(element))
                        .build();
                //把resultConfig放入result中
                results.put(resultConfig.getName(), resultConfig);
            }
        }
        //返回result
        return results;
    }    

 为该action添加拦截器

 /**
     * 添加拦截器
     * @param element 元素
     * @param context package上下文
     * @return
     * @throws ConfigurationException
     */
    protected List<InterceptorMapping> buildInterceptorList(Element element, PackageConfig.Builder context) throws ConfigurationException {
        List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>();//创建一个拦截器Map List
        NodeList interceptorRefList = element.getElementsByTagName("interceptor-ref");//获取所有的interceptor-ref

        //对interceptor-ref进行遍历
        for (int i = 0; i < interceptorRefList.getLength(); i++) {
            Element interceptorRefElement = (Element) interceptorRefList.item(i);//获取第I个interceptor-ref节点
            //如果该节点的父节点是action
            if (interceptorRefElement.getParentNode().equals(element) || interceptorRefElement.getParentNode().getNodeName().equals(element.getNodeName())) {
             //在全局拦截器中进行查找
                List<InterceptorMapping> interceptors = lookupInterceptorReference(context, interceptorRefElement);
                interceptorList.addAll(interceptors);
            }
        }
        //返回一个拦截器列表
        return interceptorList;
    }

  为该action添加异常映射

  /**
     * 通过给定的xml节点创建一个ExceptionMapping(ResultConfig)
     * @param element 节点
     * @param packageContext 包
     */
    protected List<ExceptionMappingConfig> buildExceptionMappings(Element element, PackageConfig.Builder packageContext) {
        NodeList exceptionMappingEls = element.getElementsByTagName("exception-mapping");//获取exception-mapping元素节点

        List<ExceptionMappingConfig> exceptionMappings = new ArrayList<ExceptionMappingConfig>();//创建一个异常映射list列表

        /**
         * 遍历exception-mapping元素节点
         */
        for (int i = 0; i < exceptionMappingEls.getLength(); i++) {
            Element ehElement = (Element) exceptionMappingEls.item(i);//获取第I个exception-mapping元素节点

            //如果该节点的父节点为给定的global-exception-mappings,则运行
            if (ehElement.getParentNode().equals(element) || ehElement.getParentNode().getNodeName().equals(element.getNodeName())) {
                String emName = ehElement.getAttribute("name");//获取节点元素的name属性
                String exceptionClassName = ehElement.getAttribute("exception");//获取节点元素的exception属性
                String exceptionResult = ehElement.getAttribute("result");//获取接电源是的result属性
                
                /**
                 * 把该节点组装成一个Map
                 */
                Map<String, String> params = XmlHelper.getParams(ehElement);

                //判断emName是否为空
                if (StringUtils.isEmpty(emName)) {
                    emName = exceptionResult;//若为空则把result属性的值赋给emName
                }
                //新建一个ExceptionMappingConfig对象
                ExceptionMappingConfig ehConfig = new ExceptionMappingConfig.Builder(emName, exceptionClassName, exceptionResult)
                        .addParams(params)
                        .location(DomHelper.getLocationObject(ehElement))
                        .build();
                exceptionMappings.add(ehConfig);
            }
        }

        return exceptionMappings;
    }    

  为该action添加allow-method

   /**
     * 创建allowed-method的Set
     * @param element
     * @param packageContext
     * @return
     */
    protected Set<String> buildAllowedMethods(Element element, PackageConfig.Builder packageContext) {
        NodeList allowedMethodsEls = element.getElementsByTagName("allowed-methods");//获取该节点下面的所有的allowed-methods节点

        Set<String> allowedMethods = null;//创建一个新的Set

        //如果allowed-methods的个数大于0
        if (allowedMethodsEls.getLength() > 0) {
            allowedMethods = new HashSet<String>();//实例化该Set
            Node n = allowedMethodsEls.item(0).getFirstChild();//获取该allowed-methods的第一个子节点
            //若其不为空,即存在
            if (n != null) {
                String s = n.getNodeValue().trim();//获取该节点的值
                if (s.length() > 0) {
                    allowedMethods = TextParseUtil.commaDelimitedStringToSet(s);
                }
            }
        } else if (packageContext.isStrictMethodInvocation()) {
            allowedMethods = new HashSet<String>();
        }
        //返回处理后的结果集
        return allowedMethods;
    }   

 这些配置完成之后,把该action添加到packageContext中
  然后调用:
  //为该package加载默认的action
  loadDefaultActionRef(newPackage, packageElement);

 /**
     * 为action加载默认的default-action-ref
     * @param packageContext 包
     * @param element 节点
     */
    protected void loadDefaultActionRef(PackageConfig.Builder packageContext, Element element) {
        NodeList resultTypeList = element.getElementsByTagName("default-action-ref");//获取该包下面的default-action-ref信息

        if (resultTypeList.getLength() > 0) {
            Element defaultRefElement = (Element) resultTypeList.item(0);//获取第1个该default-action-ref节点
            packageContext.defaultActionRef(defaultRefElement.getAttribute("name"));//把该节点的name放入package的defaultActionRef中
        }
    }  

  在然后实例化该packageConfig对象,并添加到DefaultConfiguration中,返回该defaultConfiguration
  ②reloads.add(child);
  如果配置需要重新更新的话,重新加载该package节点
  ③loadExtraConfiguration(doc);
  该方法未执行任何操作,该方法内容具体如下:

 /**
     * 运行子类加载document中的其他信息
     * @param doc The configuration document
     */
    protected void loadExtraConfiguration(Document doc) {
        // no op
    }   

  ③loadExtraConfiguration(doc);//这三个方法没什么好介绍的
  ④reloadRequiredPackages(reloads);
  ⑤loadExtraConfiguration(doc);
  至此,loadPackages方法执行结束
  3:StrutsXmlConfigurationProvider(struts-plugin.xml)
  同2:
  4:StrutsXmlConfigurationProvider(struts.xml)
  同2:
  5:LegacyPropertiesConfigurationProvider
  同1:
  6:用户配置
  具体情况具体分析
  7:web.xml的filter中配置的参数
  该方法是一个空实现
  8:BeanSelectionProvider
  该类中的该方法是一个空实现
  19)packageProviders.add((PackageProvider)containerProvider);
  把解析完之后的packageProvider放入packageProviders的list中
  20)Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);
  根据类型来取得该类型的实例对象名称集合(适用于同一个类型创建了多个不同名称的对象)
  21)PackageProvider provider = container.getInstance(PackageProvider.class, name);
  22)provider.init(this);
  23)provider.loadPackages();
  24)packageProviders.add(provider);
  25)rebuildRuntimeConfiguration();
  27)return packageProviders;
  这些代码,暂时未分析
  ②Container container = config.getContainer();
  获取DefaultConfiguration实体对象的Container对象(此时的Container对象是一个ContainerImpl对象)
  ③boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
  获取是否配置了国际化
  ④LocalizedTextUtil.setReloadBundles(reloadi18n);
  定义是否需要重新装载资源绑定
4、加载完配置文件之后执行的操作
  一:container.inject(this);
 
  二:init_CheckConfigurationReloading(container);

/**
     * 在FileManager中设置是否需要重新加载
     * @param container
     */
    private void init_CheckConfigurationReloading(Container container) {
  //此时FileManager对象的实体是DefaultFileManager
        FileManager fileManager = container.getInstance(FileManager.class);
        fileManager.setReloadingConfigs("true".equals(container.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)));
    } 

  三:init_CheckWebLogicWorkaround(container);

 /**
     * 该方法具体内容暂时未分析
     * @param container
     */
    private void init_CheckWebLogicWorkaround(Container container) {
        // test whether param-access workaround needs to be enabled
        if (servletContext != null && servletContext.getServerInfo() != null
                && servletContext.getServerInfo().contains("WebLogic")) {
            if (LOG.isInfoEnabled()) {
         LOG.info("WebLogic server detected. Enabling Struts parameter access work-around.");
            }
            paramsWorkaroundEnabled = true;
        } else {
            paramsWorkaroundEnabled = "true".equals(container.getInstance(String.class,
                    StrutsConstants.STRUTS_DISPATCHER_PARAMETERSWORKAROUND));
        }
    }

5、介绍StrutsPrepareAndExecuteFilter中剩余的部分
  prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);实例化一个prepare方法
  这里的PrepareOperations类的构造方法如下:

  /**
     * PrepareOperations的构造方法
     * @param servletContext
     * @param dispatcher
     */
    public PrepareOperations(ServletContext servletContext, Dispatcher dispatcher) {
        this.dispatcher = dispatcher;//实例化该类的内部变量dispatcher
        this.servletContext = servletContext;//实例化该类内部的变量servletContext
    } 

  execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);实例化一个execute方法
  这里的ExecuteOperations类的构造方法如下:

   /**
     * ExecuteOperations的构造方法
     * @param servletContext servletContext实例
     * @param dispatcher dispatcher实例
     */
    public ExecuteOperations(ServletContext servletContext, Dispatcher dispatcher) {
        this.dispatcher = dispatcher;//实例化该类的内部变量dispatcher
        this.servletContext = servletContext;//实例化该类内部的变量servletContext
    }

  this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);执行buildExcludedPatternsList方法
  该方法的具体含义目前不是很了解
  postInit(dispatcher, filterConfig);//执行postInit方法
  调用的StrutsPrepareAndExecuteFilter类中的postInit(Dispatcher dispatcher, FilterConfig filterConfig)方法如下:

  /**
     * Callback for post initialization
     */
    protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
    }

至此,struts2框架初始化结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值