自动扫描加载Struts2.3.16配置文件

最近在做架构方面的研究,采用模块化设计时,可能存在不同的模块jar包,都存在struts2的配置文件,此时如何自动加载jar包中的配置文件就成为一个问题。

    虽然struts2提供通配符和action的自动加载,但是加载的是web-inf/classes中的action配置文件,默认是不能加载jar包中的(struts2自身jar包中的 "struts-default.xml,struts-plugin.xml,struts.xml",都是在classpath下的。)。如果我们将所有的配置文件存放在一个配置文件中,这样在项目间的协同开发和测试就会出现混乱,而最好的开发模式就是每个模块都有自己的action配置文件,而系统会自动搜索到所有的配置文件,采用自动加载的方式来完成struts2的初始化。
 
首先我们分析下源码,找出修改点:
<filter>
     <filter-name>struts2</filter-name>
     <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
     <filter-name>struts2</filter-name>
     <url-pattern>/*</url-pattern>
</filter-mapping>

StrutsPrepareAndExecuteFilter的init方法

         init是Filter第一个运行的方法,我们看下struts2的核心Filter在调用init方法初始化时做哪些工作:

 public void init(FilterConfig filterConfig) throws ServletException {
        InitOperations init = new InitOperations();
        try {
          //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中
            FilterHostConfig config = new FilterHostConfig(filterConfig);

          // 初始化struts内部日志
           init.initLogging(config);

          //创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源
            Dispatcher dispatcher = init.initDispatcher(config);
            init.initStaticContentLoader(config, dispatcher);

          //初始化类属性:prepare 、execute
            prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
            execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
             this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
            //回调空的postInit方法
            postInit(dispatcher, filterConfig);
        } finally {
            init.cleanup();
        }
}

 看下FilterHostConfig ,源码如下
public class FilterHostConfig implements HostConfig {

    private FilterConfig config;
    /**
     *构造函数 
     */   
    public FilterHostConfig(FilterConfig config) {
        this.config = config;
    }
    /**
     *  根据init-param配置的param-name获取param-value的值
     */ 
    public String getInitParameter(String key) {
        return config.getInitParameter(key);
    }
       /**
         *  返回初始化参数名的List
     */
    public Iterator<String> getInitParameterNames() {
        return MakeIterator.convert(config.getInitParameterNames());
    }

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

创建并初始化Dispatcher :
 public Dispatcher initDispatcher( HostConfig filterConfig ) {
        Dispatcher dispatcher = createDispatcher(filterConfig);
        dispatcher.init();
        return dispatcher;
    }

创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher :
private Dispatcher createDispatcher( HostConfig filterConfig ) {
        Map<String, String> params = new HashMap<String, String>();
        for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
            String name = (String) e.next();
            String value = filterConfig.getInitParameter(name);
            params.put(name, value);
        }
        return new Dispatcher(filterConfig.getServletContext(), params);
    }

Dispatcher初始化,加载struts2的相关配置文件,将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.xml

     /**
     * Load configurations, including both XML and zero  -  configuration strategies,
     * and update optional settings, including whether to reload configurations and resource files.
     */
     public   void  init() {

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

         try  {
            init_FileManager();
                             //加载org/apache/struts2/default.properties
            init_DefaultProperties();  // [1]
            init_TraditionalXmlConfigurations();  // [2]     //加载struts-default.xml,struts-plugin.xml,struts.xml
            init_LegacyStrutsProperties();  // [3]
            init_CustomConfigurationProviders();  // [5] 加载自定义的配置
            init_FilterInitParameters() ;  // [6]     //Filter的初始化参数
            init_AliasStandardObjects() ;  // [7]

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

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

      private   void  init_CustomConfigurationProviders() {
        String configProvs =  initParams  .get( "configProviders"  );
         if  (configProvs !=  null ) {
            String[] classes = configProvs.split(  "\\s*[,]\\s*"  );
             for  (String cname : classes) {
                 try  {
                    Class cls = ClassLoaderUtil. loadClass(cname,  this  .getClass());
                    ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
                     configurationManager  .addContainerProvider(prov);
                }  catch  (InstantiationException e) {
                     throw   new  ConfigurationException(  "Unable to instantiate provider: " +cname, e);
                }  catch  (IllegalAccessException e) {
                     throw   new  ConfigurationException(  "Unable to access provider: " +cname, e);
                }  catch  (ClassNotFoundException e) {
                     throw   new  ConfigurationException(  "Unable to locate provider class: " +cname, e);
                }
            }
        }
    }

从上面源码可以看出,只要配置 configProviders参数,并且实现了  ConfigurationProvider接口,struts2就会自动加载相应的配置。
下面的代码实现,主要借助于spring的PathMatchingResourcePatternResolver,自动扫描jar包中的文件,然后转换成URL的形式,继承getConfigurationUrls方法。

 

package com.XXX.xx.contrl.context;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.util.location.LocatableProperties;

/**
*
* @ClassName: CutomConfigurationProvider
* @Description:
* @author linhz
* @date 2014-8-14 下午05:38:25
*
*/
public class CutomConfigurationProvider extends XmlConfigurationProvider {
    private static final String FILE_PATTERN = "classpath*:/conf/struts/plugins/**/struts-*.xml";

    public CutomConfigurationProvider() {
          Map<String, String> mappings = new HashMap<String, String>();

          mappings.put(
                              "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN",
                              "struts-2.0.dtd");
          mappings.put(
                              "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN",
                              "struts-2.1.dtd");
          mappings.put(
                              "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN",
                              "struts-2.1.7.dtd");
          mappings.put(
                              "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN",
                              "struts-2.3.dtd");
          setDtdMappings(mappings);
    }

    /*
      * (non-Javadoc)
      *
      * @see com.opensymphony.xwork2.config.ContainerProvider#needsReload()
      */
    @Override
    public boolean needsReload() {
          return true;
    }

    /*
      * (non-Javadoc)
      *
      * @see
      * com.opensymphony.xwork2.config.ContainerProvider#register(com.opensymphony
      * .xwork2.inject.ContainerBuilder,
      * com.opensymphony.xwork2.util.location.LocatableProperties)
      */
    @Override
    public void register(ContainerBuilder containerBuilder,
              LocatableProperties props) throws ConfigurationException {
          super.register(containerBuilder, props);
    }

    /*
      * (non-Javadoc)
      *
      * @see com.opensymphony.xwork2.config.PackageProvider#loadPackages()
      */
    @Override
    public void loadPackages() throws ConfigurationException {
          super.loadPackages();
    }

    @Override
    protected Iterator<URL> getConfigurationUrls(String fileName)
              throws IOException {
          List<URL> urls = new ArrayList<URL>();
          Resource[] resources = getAllResourcesUrl();
          for (Resource resource : resources) {
              urls.add(resource.getURL());
          }

          return urls.iterator();
    }

    /**
      * 获取系统中需要搜寻的struts的配置
      *
      * @return
      * @throws IOException
      */
    private Resource[] getAllResourcesUrl() {
          ResourcePatternResolver resoler = new PathMatchingResourcePatternResolver();
          try {
              return resoler.getResources(FILE_PATTERN);
          } catch (IOException e) {
              e.printStackTrace();
          }
          return new Resource[0];
    }

}

然后在web.xml中添加如下的代码:

<!-- struts2 filter begin -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

<init-param>
     <param-name>configProviders</param-name>
     <param-value>com.xxx.xx.contrl.context.CutomConfigurationProvider</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>

<!-- struts2 filter end -->
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值