Struts2.3.14分析-初始化1



Web.xml

在任何基于StrutsWeb程序中,第一项需要配置的就是Web.xml,将所有的请求交给StrutsPrepareAndExecuteFilter过滤器进行过滤。

<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 初始化

StrutsPrepareAndExecuteFilter是实现的Filter接口的过滤器,必须实现init, doFilterDestory方法。init方法主要任务是初始化Filter相关参数,加载配置参数,很显然对Struts.xml文件的解析也是在该方法调用的过程中完成的。

下面我们就来剖析一下init方法


public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
    protected PrepareOperations prepare;
    protected ExecuteOperations execute;
	protected List<Pattern> excludedPatterns = null;

public void init(FilterConfig filterConfig) throws ServletException {
        InitOperations init = new InitOperations();
        try {
			# FilterHostConfig对FilterConfig新型简易封装
            FilterHostConfig config = new FilterHostConfig(filterConfig);
            # 初始化 Struts 日志类
init.initLogging(config);
# Dispatcher 封装ServletContext和FilterConfig, 会调用dispatcher的init 方法
            Dispatcher dispatcher = init.initDispatcher(config);
            init.initStaticContentLoader(config, dispatcher);

            prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
            execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
			this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

            postInit(dispatcher, filterConfig);
        } finally {
            init.cleanup();
        }

}

InitOperation类

public class InitOperations {

    public InitOperations() {
    }

	// 创建Dispatch对象
public Dispatcher initDispatcher( HostConfig filterConfig ) {
        Dispatcher dispatcher = createDispatcher(filterConfig);
        dispatcher.init();
        return dispatcher;
}

private Dispatcher createDispatcher( HostConfig filterConfig ) {
	//保存Web.xml中filter的配置参数
        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 类

private ServletContext servletContext;
private Map<String, String> initParams;
private ConfigurationManager configurationManager;


public Dispatcher(ServletContext servletContext, Map<String, String> initParams) {
        this.servletContext = servletContext;
        this.initParams = initParams;
}

//主角登场, 读取并解析配置文件
public void init() {
    	if (configurationManager == null) {
    		configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
	#BeanSelectionProver.DEFAULT_BEAN_NAME 就是struts
    	}
     try {
		# 都会调用 configurationManager.addContainerProvider方法
     	init_FileManager();
     	init_DefaultProperties();
     	init_TraditionalXmlConfigurations(); //完成struts-default.xml,struts-plugin.xml,struts.xml相关配置对象ConfigurationProvider创建,并保存在ConfigurationManager的集合中,由此我们也知道了这三者的先后加载顺序了
     	init_LegacyStrutsProperties(); 
     	init_CustomConfigurationProviders();
      	init_FilterInitParameters() ; 
    		init_AliasStandardObjects() ; 

  		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_TraditionalXmlConfigurations() {
        String configPaths = initParams.get("config");
        if (configPaths == null) {
			# struts-default.xml,struts-plugin.xml,struts.xml
            configPaths = DEFAULT_CONFIGURATION_PATHS;
        }
        String[] files = configPaths.split("\\s*[,]\\s*");
        for (String file : files) {
            if (file.endsWith(".xml")) {
                if ("xwork.xml".equals(file)) {
                    configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
                } else {
                # 调用 createStrutsXmlConfigurationProvider configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
                }
            } else {
                throw new IllegalArgumentException("Invalid configuration file name");
            }
        }
    }

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

private Container init_PreloadConfiguration() {
        Configuration config = configurationManager.getConfiguration();
        Container container = config.getContainer();

        boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
        LocalizedTextUtil.setReloadBundles(reloadi18n);

        ContainerHolder.store(container);
        return container;
    }

StrutsXmlConfigurationProvider类

init_TraditionalXmlConfigurations方法调用是会创建三个StrutsXmlConfigurationProvider对象,其filename分别是struts-default.xml,struts-plugin.xml, struts.xml

public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {     
    private File baseDir = null;
    private String filename;      
    private ServletContext servletContext;

public StrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
        super(filename, errorIfMissing);
        this.servletContext = ctx;
        this.filename = filename;
        reloadKey = "configurationReload-"+filename;
        ……
        File file = new File(filename);
        if (file.getParent() != null) {
            this.baseDir = file.getParentFile();
        }
}
//其他属性和方法
}

XmlConfigurationProvider

public class XmlConfigurationProvider implements ConfigurationProvider {     
    private String configFileName;   
    private boolean errorIfMissing;    

    public XmlConfigurationProvider(String filename, boolean errorIfMissing) {
        this.configFileName = filename;
        this.errorIfMissing = errorIfMissing;
        ……
        setDtdMappings(mappings);
}

ConfigurationProvider接口

public interface ConfigurationProvider extends ContainerProvider, PackageProvider {
}

ContainerProvider 接口

public interface ContainerProvider {
    public void destroy();     
    public void init(Configuration configuration) throws ConfigurationException;     
    public boolean needsReload();    
    public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;    
}

ConfigurationManager类

public class ConfigurationManager {    
	    protected Configuration configuration;	   
	    private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<ContainerProvider>();
	    private List<PackageProvider> packageProviders = new CopyOnWriteArrayList<PackageProvider>();
	    protected String defaultFrameworkBeanName;

public synchronized Configuration getConfiguration() {
        		if (configuration == null) {
            		setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));
            		try {
				# 调用DefaultConfiguration的reloadContainer方法
                	configuration.reloadContainer(getContainerProviders());
            		} catch (ConfigurationException e) {
                		setConfiguration(null);
                		throw new ConfigurationException("Unable to load configuration.", e);
            		}
        		} else {
            		conditionalReload();
        		}
        			return configuration;
   		 }

    		public synchronized void setConfiguration(Configuration configuration) {
      		this.configuration = configuration;
    		}

	    //用集合List保存所用配置相关的ContainerProvider     
public void addContainerProvider(ContainerProvider provider) {
		if (!containerProviders.contains(provider)) {
   		containerProviders.add(provider);
}
   }

DefaultConfiguration类

public class DefaultConfiguration implements Configuration {

    protected static final Logger LOG = LoggerFactory.getLogger(DefaultConfiguration.class);


    // Programmatic Action Configurations
    protected Map<String, PackageConfig> packageContexts = new LinkedHashMap<String, PackageConfig>();
    protected RuntimeConfiguration runtimeConfiguration;
    protected Container container;
    protected String defaultFrameworkBeanName;
    protected Set<String> loadedFileNames = new TreeSet<String>();
protected List<UnknownHandlerConfig> unknownHandlerStack;

//完成集合中所有ConfigurationProvider的解析
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
        packageContexts.clear();
        loadedFileNames.clear();
        List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();

        ContainerProperties props = new ContainerProperties();
        ContainerBuilder builder = new ContainerBuilder();
        for (final ContainerProvider containerProvider : providers)
        {
			//遍历集合,对每个containerProvider进行初始化,保存配置信息,
#对struts.xml文件加载也在此过程中完成(调用XmlConfigurationProvider的init方法和StrutsXmlConfigurationProvider的register方法)
            containerProvider.init(this);
            containerProvider.register(builder, props);
        }
        props.setConstants(builder);

        builder.factory(Configuration.class, new Factory<Configuration>() {
            public Configuration create(Context context) throws Exception {
                return DefaultConfiguration.this;
            }
        });

        ActionContext oldContext = ActionContext.getContext();
        try {
            // Set the bootstrap container for the purposes of factory creation
            Container bootstrap = createBootstrapContainer();
            setContext(bootstrap);
            container = builder.create(false);
            setContext(container);
            objectFactory = container.getInstance(ObjectFactory.class);

            // Process the configuration providers first
            for (final ContainerProvider containerProvider : providers)
            {
                if (containerProvider instanceof PackageProvider) {
                    container.inject(containerProvider);
                    ((PackageProvider)containerProvider).loadPackages();
                    packageProviders.add((PackageProvider)containerProvider);
                }
            }

            // Then process any package providers from the plugins
            Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);
            if (packageProviderNames != null) {
                for (String name : packageProviderNames) {
                    PackageProvider provider = container.getInstance(PackageProvider.class, name);
                    provider.init(this);
                    provider.loadPackages();
                    packageProviders.add(provider);
                }
            }

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

由于篇幅的原因,对Struts.xml解析过程将放在下一篇文章中详细阐述,这是我们使用struts框架是主要的配置文件,很有必要了解struts是如何加载的。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值