目录
第二步:往ConfigurationManager添加一个FileManagerProvider
第三步:往ConfigurationManager添加一个DefaultPropertiesProvider
第四步:往ConfigurationManager添加一个StrutsXmlConfigurationProvider
第五步:往ConfigurationManager添加一个PropertiesConfigurationProvider
第六步:往ConfigurationManager添加用户自定义的xmlprovider
第七步:往ConfigurationManager添加一个ConfigurationProvider实现类用于解析Filter参数
第八步:往ConfigurationManager添加一个BeanSelectionProvider
Dispatcher
接下来的语句就是:(初始化分配器)
dispatcher = init.initDispatcher(config);
我们进行源码跟踪到:
org.apache.struts2.dispatcher.InitOperation
public Dispatcher initDispatcher(HostConfig filterConfig) {
//创建
Dispatcher dispatcher = this.createDispatcher(filterConfig);
//初始化
dispatcher.init();
return dispatcher;
}
....
protected Dispatcher createDispatcher(HostConfig filterConfig) {
Map<String, String> params = new HashMap();
//遍历filterConfig把init-param全部拿出来,就是那些在web.xml配置在Filter标签里面的初始化参数
Iterator e = filterConfig.getInitParameterNames();
while(e.hasNext()) {
String name = (String)e.next();
String value = filterConfig.getInitParameter(name);
params.put(name, value);
}
//创建
return new Dispatcher(filterConfig.getServletContext(), params);
}
接下来看下一条语句:
dispatcher.init();
public void init() {
if (this.configurationManager == null) {
//配置文件管理器
this.configurationManager = this.createConfigurationManager("default");
}
try {
//文件管理器
this.init_FileManager();
init_DefaultProperties(); //加入默认配置供给器,解析org/apache/struts2/default.properties
init_TraditionalXmlConfigurations(); // struts-default.xml
init_LegacyStrutsProperties(); // struts-default.xml,struts-plugin.xml,struts.xml
init_CustomConfigurationProviders(); // struts.properties
init_FilterInitParameters() ; // default.properties
init_AliasStandardObjects() ; // struts.custom.properties
Container container = this.init_PreloadConfiguration();
container.inject(this);
this.init_CheckWebLogicWorkaround(container);
if (!dispatcherListeners.isEmpty()) {
Iterator i$ = dispatcherListeners.iterator();
while(i$.hasNext()) {
DispatcherListener l = (DispatcherListener)i$.next();
l.dispatcherInitialized(this);
}
}
this.errorHandler.init(this.servletContext);
} catch (Exception var4) {
LOG.error("Dispatcher initialization failed", var4);
throw new StrutsException(var4);
}
}
第一步:创建ConfigurationManager。
/**
* ConfigurationManager - central for XWork Configuration management, including its ConfigurationProvider.
*/
public class ConfigurationManager {
protected Configuration configuration;
private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<ContainerProvider>();
private List<PackageProvider> packageProviders = new CopyOnWriteArrayList<PackageProvider>();
public ConfigurationManager()
public ConfigurationManager(String name)
public synchronized Configuration getConfiguration()
protected Configuration createConfiguration(String beanName)
public synchronized void setConfiguration(Configuration configuration)
public List<ContainerProvider> getContainerProviders()
public void setContainerProviders(List<ContainerProvider> containerProviders)
public void addContainerProvider(ContainerProvider provider)
public void clearContainerProviders()
private void clearContainerProvider(ContainerProvider containerProvider)
public synchronized void destroyConfiguration()
public synchronized void conditionalReload()
private void updateReloadConfigsFlag()
private boolean needReloadPackageProviders()
private boolean needReloadContainerProviders(List<ContainerProvider> providers)
private void reloadProviders(List<ContainerProvider> providers)
public synchronized void reload()
}
从源码中我们可以看到三个属性:
configuration(Configuration):存储配置信息;
containerProviders(List<ContainerProvider>):对应的 ContainerProvider 用来加载<constants>和<bean>两种元素以及default.properties,struts.properties文件中声明的常量(保存在Key和InternalFactory类中,最终保存在factories中,然后将容器元素从文件中加载后对象化了也就是生成了Container类)。之所以说它是容器元素,是因为它们配置的信息最终反映到Container对象中,也就是容器了。
packageProviders(List<PackageProvider>):PackageProvider 用来加载我们经常配置的<package>元素(保存在PackageConfig这个类中)。
那么ConfigurationManager这个类的功能便是明显了:维护一个Configuration对象,管理配置信息。
接下来我们来看看Configuration、PackageProvider和ContainerProvider这三个类:
package com.opensymphony.xwork2.config;
public interface Configuration extends Serializable {
void rebuildRuntimeConfiguration();
PackageConfig getPackageConfig(String var1);
Set<String> getPackageConfigNames();
Map<String, PackageConfig> getPackageConfigs();
RuntimeConfiguration getRuntimeConfiguration();
void addPackageConfig(String var1, PackageConfig var2);
PackageConfig removePackageConfig(String var1);
void destroy();
List<PackageProvider> reloadContainer(List<ContainerProvider> var1) throws ConfigurationException;
Container getContainer();
Set<String> getLoadedFileNames();
List<UnknownHandlerConfig> getUnknownHandlerStack();
void setUnknownHandlerStack(List<UnknownHandlerConfig> var1);
}
该接口只是定义了行为,数据的存储还需要数据结构,这就在实现类了。我们来看一下它的实现类DefaultConfiguration :
public class DefaultConfiguration implements Configuration {
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;
ObjectFactory objectFactory;
}
其中还有个RuntimeConfiguration属性,它封装了运行时的Action配置等信息。
下面是两个Provider以及他们整合成的同一接口ConfigurationProvider的源代码:
package com.opensymphony.xwork2.config;
public interface PackageProvider {
void init(Configuration var1) throws ConfigurationException;
boolean needsReload();
void loadPackages() throws ConfigurationException;
}
package com.opensymphony.xwork2.config;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.util.location.LocatableProperties;
public interface ContainerProvider {
void destroy();
void init(Configuration var1) throws ConfigurationException;
boolean needsReload();
void register(ContainerBuilder var1, LocatableProperties var2) throws ConfigurationException;
}
package com.opensymphony.xwork2.config;
public interface ConfigurationProvider extends ContainerProvider, PackageProvider {
}
我们可以重点关注的两个方法:
loadPackages():加载配置信息;
register(ContainerBuilder var1, LocatableProperties var2):将<bean>和<constant>信息加载到Container中。(这里可以涉及到的参数ContainerBuilder,从字面意义上我们已经可以知道了这是一个构建器(构建者模式)。也就是Container最终是通过ContainerBuilder构造出来的。)
到这里我们可以大概整理一下struts是如何加载配置文件的:
由×××Provider将配置文件加载到PackageConfig、Key等实体类中,然后加载(loadPackages())到Configuration进行保存, 其中对于<bean>这样的配置信息会被注册(register(...))到ContainerBuilder的类中,再由ContainerBuilder构造出Container。最后由ConfigurationManager来维护这些配置信息。
第二步:往ConfigurationManager添加一个FileManagerProvider
this.init_FileManager();
private void init_FileManager() throws ClassNotFoundException {
String fileManagerFactoryClassName;
Class fileManagerFactoryClass;
if (this.initParams.containsKey("struts.fileManager")) {//初始化参数中是否由“struts.fileManager”,一般没有
fileManagerFactoryClassName = (String)this.initParams.get("struts.fileManager");
fileManagerFactoryClass = Class.forName(fileManagerFactoryClassName);
LOG.info("Custom FileManager specified: {}", fileManagerFactoryClassName);
this.configurationManager.addContainerProvider(new FileManagerProvider(fileManagerFactoryClass, fileManagerFactoryClass.getSimpleName()));
} else {
this.configurationManager.addContainerProvider(new FileManagerProvider(JBossFileManager.class, "jboss"));
}
if (this.initParams.containsKey("struts.fileManagerFactory")) {//初始化参数中是否由“struts.fileManagerFactory”,一般没有
fileManagerFactoryClassName = (String)this.initParams.get("struts.fileManagerFactory");
fileManagerFactoryClass = Class.forName(fileManagerFactoryClassName);
LOG.info("Custom FileManagerFactory specified: {}", fileManagerFactoryClassName);
this.configurationManager.addContainerProvider(new FileManagerFactoryProvider(fileManagerFactoryClass));
}
}
程序执行:
this.configurationManager.addContainerProvider(new FileManagerProvider(JBossFileManager.class, "jboss"));
这一条分支语句,也就是一个FileManagerProvider对象被加入到了List中。我们看看FileManagerProvider:
package com.opensymphony.xwork2.config;
public class FileManagerProvider implements ContainerProvider {
private Class<? extends FileManager> fileManagerClass;
private String name;
public FileManagerProvider(Class<? extends FileManager> fileManagerClass, String name) {
this.fileManagerClass = fileManagerClass;
this.name = name;
}
public void destroy() {
}
public void init(Configuration configuration) throws ConfigurationException {
}
public boolean needsReload() {
return false;
}
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
builder.factory(FileManager.class, this.name, this.fileManagerClass, Scope.SINGLETON);
}
}
实现了ContainerProvider接口,看register()的实现,它调用了参数ContainerBuiler的factory()方法,就是向ContainerBuilder注入参数的,创建一个FileManager对象。关于FileManager类:
package com.opensymphony.xwork2;
public interface FileManager {
void setReloadingConfigs(boolean var1);
boolean fileNeedsReloading(String var1);
boolean fileNeedsReloading(URL var1);
InputStream loadFile(URL var1);
void monitorFile(URL var1);
URL normalizeToFileProtocol(URL var1);
boolean support();
boolean internal();
Collection<? extends URL> getAllPhysicalUrls(URL var1) throws IOException;
}
看接口开头的注释,可以知道这个类的功能就是访问文件系统中的文件并且监控文件是否被修改了。如果被修改了,可能就要重新载入了。那么之前factory()方法会创建出什么类呢?也就是参数传递进去的JBossFileManager类了。
总结一下,就是init_FileManager的功能就是往configurationManager的List<ContainerProvider>属性添加一个元素FileManagerProvider。接下来的工作都类似了。所有添加Provider的工作都是为了最终创建出一个可用的Container(到时创建Container时,会一一调用这些provider的register()),以及对象化的事件映射配置元素。
第三步:往ConfigurationManager添加一个DefaultPropertiesProvider
this.init_DefaultProperties();
package org.apache.struts2.config;
public class DefaultPropertiesProvider extends PropertiesConfigurationProvider {
public DefaultPropertiesProvider() {
}
public void destroy() {
}
public void init(Configuration configuration) throws ConfigurationException {
}
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
try {
PropertiesSettings defaultSettings = new PropertiesSettings("org/apache/struts2/default");
this.loadSettings(props, defaultSettings);
} catch (Exception var4) {
throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", var4);
}
}
}
package org.apache.struts2.config;
public class PropertiesConfigurationProvider implements ConfigurationProvider {
...
protected void loadSettings(LocatableProperties props, Settings settings) {
Iterator i = settings.list();
while(i.hasNext()) {
String name = (String)i.next();
props.setProperty(name, settings.get(name), settings.getLocation(name));
}
}
}
从名字上来看我们就可以推测出这一步的作用就是加载properties文件。我们可以看看PropertiesSetting这个实体类:
package org.apache.struts2.config;
class PropertiesSettings implements Settings {
private static final Logger LOG = LogManager.getLogger(PropertiesSettings.class);
private LocatableProperties settings;
public PropertiesSettings(String name) {
URL settingsUrl = ClassLoaderUtil.getResource(name + ".properties", this.getClass());
if (settingsUrl == null) {
LOG.debug("{}.properties missing", name);
this.settings = new LocatableProperties();
} else {
this.settings = new LocatableProperties(new LocationImpl((String)null, settingsUrl.toString()));
try {
InputStream in = settingsUrl.openStream();
Throwable var4 = null;
try {
this.settings.load(in);
} catch (Throwable var14) {
var4 = var14;
throw var14;
} finally {
if (in != null) {
if (var4 != null) {
try {
in.close();
} catch (Throwable var13) {
var4.addSuppressed(var13);
}
} else {
in.close();
}
}
}
} catch (IOException var16) {
throw new StrutsException("Could not load " + name + ".properties: " + var16, var16);
}
}
}
...
}
具体的我们就不说了,从下面两句代码应该可以大概推测是加载org/apche/struts2/default.properties。
PropertiesSettings defaultSettings = new PropertiesSettings("org/apache/struts2/default");
URL settingsUrl = ClassLoaderUtil.getResource(name + ".properties", this.getClass());
第四步:往ConfigurationManager添加一个StrutsXmlConfigurationProvider
this.init_TraditionalXmlConfigurations();
private void init_TraditionalXmlConfigurations() {
String configPaths = (String)this.initParams.get("config");
if (configPaths == null) {
configPaths = "struts-default.xml,struts-plugin.xml,struts.xml";
}
String[] files = configPaths.split("\\s*[,]\\s*");
String[] arr$ = files;
int len$ = files.length;
for(int i$ = 0; i$ < len$; ++i$) {
String file = arr$[i$];
if (!file.endsWith(".xml")) {
throw new IllegalArgumentException("Invalid configuration file name");
}
this.configurationManager.addContainerProvider(this.createStrutsXmlConfigurationProvider(file, false, this.servletContext));
}
}
容易看出加载的文件是:struts-default.xml,struts-plugin.xml,struts.xml 这样的.xml文件。
我们看一下它所继承的父类:XmlConfigurationProvider的register方法
package com.opensymphony.xwork2.config.providers;
public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
LOG.trace("Parsing configuration file [{}]", this.configFileName);
Map<String, Node> loadedBeans = new HashMap();
Iterator i$ = this.documents.iterator();
while(i$.hasNext()) {
Document doc = (Document)i$.next();
Element rootElement = doc.getDocumentElement();
NodeList children = rootElement.getChildNodes();
int childSize = children.getLength();
for(int i = 0; i < childSize; ++i) {
Node childNode = children.item(i);
if (childNode instanceof Element) {
Element child = (Element)childNode;
String nodeName = child.getNodeName();
String type;
String name;
if ("bean".equals(nodeName)) {//加载<bean>结点信息
type = child.getAttribute("type");
name = child.getAttribute("name");
String impl = child.getAttribute("class");
String onlyStatic = child.getAttribute("static");
String scopeStr = child.getAttribute("scope");
boolean optional = "true".equals(child.getAttribute("optional"));
Scope scope = Scope.SINGLETON;//Scope为枚举类型,作用域
if ("prototype".equals(scopeStr)) {
scope = Scope.PROTOTYPE;
} else if ("request".equals(scopeStr)) {
scope = Scope.REQUEST;
} else if ("session".equals(scopeStr)) {
scope = Scope.SESSION;
} else if ("singleton".equals(scopeStr)) {
scope = Scope.SINGLETON;
} else if ("thread".equals(scopeStr)) {
scope = Scope.THREAD;
}
if (StringUtils.isEmpty(name)) {//<bean>的name属性为空则初始化为default
name = "default";
}
try {
Class classImpl = ClassLoaderUtil.loadClass(impl, this.getClass());
Class classType = classImpl;
if (StringUtils.isNotEmpty(type)) {
classType = ClassLoaderUtil.loadClass(type, this.getClass());
}
if ("true".equals(onlyStatic)) {
classImpl.getDeclaredClasses();
containerBuilder.injectStatics(new Class[]{classImpl});
} else {
if (containerBuilder.contains(classType, name)) {
Location loc = LocationUtils.getLocation(loadedBeans.get(classType.getName() + name));
if (this.throwExceptionOnDuplicateBeans) {
throw new ConfigurationException("Bean type " + classType + " with the name " + name + " has already been loaded by " + loc, child);
}
}
classImpl.getDeclaredConstructors();
LOG.debug("Loaded type: {} name: {} impl: {}", type, name, impl);
containerBuilder.factory(classType, name, new LocatableFactory(name, classType, classImpl, scope, childNode), scope);
}
loadedBeans.put(classType.getName() + name, child);
} catch (Throwable var23) {
if (!optional) {
throw new ConfigurationException("Unable to load bean: type:" + type + " class:" + impl, var23, childNode);
}
LOG.debug("Unable to load optional class: {}", impl);
}
} else if ("constant".equals(nodeName)) {//加载<constant>结点
type = child.getAttribute("name");
name = child.getAttribute("value");
if (this.valueSubstitutor != null) {
LOG.debug("Substituting value [{}] using [{}]", name, this.valueSubstitutor.getClass().getName());
name = this.valueSubstitutor.substitute(name);
}
//常量信息存放在Properties类中
props.setProperty(type, name, childNode);
} else if (nodeName.equals("unknown-handler-stack")) {
List<UnknownHandlerConfig> unknownHandlerStack = new ArrayList();
NodeList unknownHandlers = child.getElementsByTagName("unknown-handler-ref");
int unknownHandlersSize = unknownHandlers.getLength();
for(int k = 0; k < unknownHandlersSize; ++k) {
Element unknownHandler = (Element)unknownHandlers.item(k);
Location location = LocationUtils.getLocation(unknownHandler);
unknownHandlerStack.add(new UnknownHandlerConfig(unknownHandler.getAttribute("name"), location));
}
if (!unknownHandlerStack.isEmpty()) {
this.configuration.setUnknownHandlerStack(unknownHandlerStack);
}
}
}
}
}
}
可以看到加载的是<bean> <constant> <unknow-handler-stack>这一结点的信息,其中<constant>保存的是常量信息,封装在Properties类中(继承了HashTable)。
接着看loadPackage这个方法:
public void loadPackages() throws ConfigurationException {
List<Element> reloads = new ArrayList();
this.verifyPackageStructure();
Iterator i$ = this.documents.iterator();
Document doc;
while(i$.hasNext()) {
doc = (Document)i$.next();
Element rootElement = doc.getDocumentElement();
NodeList children = rootElement.getChildNodes();
int childSize = children.getLength();
for(int i = 0; i < childSize; ++i) {
Node childNode = children.item(i);
if (childNode instanceof Element) {
Element child = (Element)childNode;
String nodeName = child.getNodeName();
if ("package".equals(nodeName)) {//加载<package>结点
PackageConfig cfg = this.addPackage(child);
if (cfg.isNeedsRefresh()) {
reloads.add(child);
}
}
}
}
this.loadExtraConfiguration(doc);
}
if (reloads.size() > 0) {
//这个方法涉及到了extend属性,尝试找到parent package
this.reloadRequiredPackages(reloads);
}
i$ = this.documents.iterator();
while(i$.hasNext()) {
doc = (Document)i$.next();
this.loadExtraConfiguration(doc);
}
this.documents.clear();
this.declaredPackages.clear();
this.configuration = null;
}
最关键的已经代码当然就是 if ("package".equals(nodeName)) 了,很明显就是加载<package>结点信息了。封装在PackageConfig,有兴趣可以自己看看,里面会一些明显的属性名称如:Action、Result等。
第五步:往ConfigurationManager添加一个PropertiesConfigurationProvider
this.init_LegacyStrutsProperties();
该方法添加的是PropertiesConfigurationProvider。
package org.apache.struts2.config;
public class PropertiesConfigurationProvider implements ConfigurationProvider {
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
DefaultSettings settings = new DefaultSettings();
this.loadSettings(props, settings);
}
protected void loadSettings(LocatableProperties props, Settings settings) {
Iterator i = settings.list();
while(i.hasNext()) {
String name = (String)i.next();
props.setProperty(name, settings.get(name), settings.getLocation(name));
}
}
}
可以看到register方法中,有一个DefaultSetting的类,我们看看这个类中加载的应该是什么信息。
package org.apache.struts2.config;
public class DefaultSettings implements Settings {
private static final Logger LOG = LogManager.getLogger(DefaultSettings.class);
private Settings delegate;
public DefaultSettings() {
ArrayList list = new ArrayList();
try {
list.add(new PropertiesSettings("struts"));
} catch (Exception var7) {
LOG.warn("DefaultSettings: Could not find or error in struts.properties", var7);
}
this.delegate = new DelegatingSettings(list);
String files = this.delegate.get("struts.custom.properties");
if (files != null) {
StringTokenizer customProperties = new StringTokenizer(files, ",");
while(customProperties.hasMoreTokens()) {
String name = customProperties.nextToken();
try {
list.add(new PropertiesSettings(name));
} catch (Exception var6) {
LOG.error("DefaultSettings: Could not find {}.properties. Skipping.", name);
}
}
this.delegate = new DelegatingSettings(list);
}
}
public Location getLocation(String name) {
return this.delegate.getLocation(name);
}
public String get(String aName) throws IllegalArgumentException {
return this.delegate.get(aName);
}
public Iterator list() {
return this.delegate.list();
}
}
仍然用到了PropertiesSetting,那么应该就是struts.properties这个文件了。我们就不细看下去了。
第六步:往ConfigurationManager添加用户自定义的xmlprovider
private void init_CustomConfigurationProviders() {
//这里应该是找到自定义xmlProviders的配置信息
String configProvs = (String)this.initParams.get("configProviders");
if (configProvs != null) {
String[] classes = configProvs.split("\\s*[,]\\s*");
String[] arr$ = classes;
int len$ = classes.length;
for(int i$ = 0; i$ < len$; ++i$) {
String cname = arr$[i$];
try {
//加载×××Provider类
Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
if (prov instanceof ServletContextAwareConfigurationProvider) {
((ServletContextAwareConfigurationProvider)prov).initWithContext(this.servletContext);
}
//加入到configurationManager中
this.configurationManager.addContainerProvider(prov);
} catch (InstantiationException var9) {
throw new ConfigurationException("Unable to instantiate provider: " + cname, var9);
} catch (IllegalAccessException var10) {
throw new ConfigurationException("Unable to access provider: " + cname, var10);
} catch (ClassNotFoundException var11) {
throw new ConfigurationException("Unable to locate provider class: " + cname, var11);
}
}
}
}
主要是作为struus2框架提供给用户的扩展点。
第七步:往ConfigurationManager添加一个ConfigurationProvider实现类用于解析Filter参数
private void init_FilterInitParameters() {
this.configurationManager.addContainerProvider(new ConfigurationProvider() {
public void destroy() {
}
public void init(Configuration configuration) throws ConfigurationException {
}
public void loadPackages() throws ConfigurationException {
}
public boolean needsReload() {
return false;
}
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
//可以注意一下这里已经不是builder.register了。可以推测一下LocatableProperties是什么作用。
props.putAll(Dispatcher.this.initParams);
}
});
}
用了一个匿名内部类,将filter参数放入容器中,被容器保管。这样,在action中也可以很方便的访问filter参数。
第八步:往ConfigurationManager添加一个BeanSelectionProvider
private void init_AliasStandardObjects() {
this.configurationManager.addContainerProvider(new DefaultBeanSelectionProvider());
}
接下来的这部分学习笔记,是笔者自己猜测的,不保证正确性。
package org.apache.struts2.config;
public class DefaultBeanSelectionProvider extends AbstractBeanSelectionProvider {
private static final Logger LOG = LogManager.getLogger(DefaultBeanSelectionProvider.class);
public DefaultBeanSelectionProvider() {
}
public void register(ContainerBuilder builder, LocatableProperties props) {
this.alias(ObjectFactory.class, "struts.objectFactory", builder, props);
this.alias(ActionFactory.class, "struts.objectFactory.actionFactory", builder, props);
this.alias(ResultFactory.class, "struts.objectFactory.resultFactory", builder, props);
this.alias(ConverterFactory.class, "struts.objectFactory.converterFactory", builder, props);
this.alias(InterceptorFactory.class, "struts.objectFactory.interceptorFactory", builder, props);
this.alias(ValidatorFactory.class, "struts.objectFactory.validatorFactory", builder, props);
this.alias(UnknownHandlerFactory.class, "struts.objectFactory.unknownHandlerFactory", builder, props);
this.alias(FileManagerFactory.class, "struts.fileManagerFactory", builder, props, Scope.SINGLETON);
this.alias(XWorkConverter.class, "struts.xworkConverter", builder, props);
this.alias(CollectionConverter.class, "struts.converter.collection", builder, props);
this.alias(ArrayConverter.class, "struts.converter.array", builder, props);
this.alias(DateConverter.class, "struts.converter.date", builder, props);
this.alias(NumberConverter.class, "struts.converter.number", builder, props);
this.alias(StringConverter.class, "struts.converter.string", builder, props);
this.alias(ConversionPropertiesProcessor.class, "struts.converter.properties.processor", builder, props);
this.alias(ConversionFileProcessor.class, "struts.converter.file.processor", builder, props);
this.alias(ConversionAnnotationProcessor.class, "struts.converter.annotation.processor", builder, props);
this.alias(TypeConverterCreator.class, "struts.converter.creator", builder, props);
this.alias(TypeConverterHolder.class, "struts..converter.holder", builder, props);
this.alias(TextProvider.class, "struts.xworkTextProvider", builder, props, Scope.PROTOTYPE);
this.alias(TextProvider.class, "struts.textProvider", builder, props, Scope.PROTOTYPE);
this.alias(TextProviderFactory.class, "struts.textProviderFactory", builder, props, Scope.PROTOTYPE);
this.alias(LocaleProviderFactory.class, "struts.localeProviderFactory", builder, props);
this.alias(LocalizedTextProvider.class, "struts.localizedTextProvider", builder, props);
this.alias(ActionProxyFactory.class, "struts.actionProxyFactory", builder, props);
this.alias(ObjectTypeDeterminer.class, "struts.objectTypeDeterminer", builder, props);
this.alias(ActionMapper.class, "struts.mapper.class", builder, props);
this.alias(MultiPartRequest.class, "struts.multipart.parser", builder, props, Scope.PROTOTYPE);
this.alias(FreemarkerManager.class, "struts.freemarker.manager.classname", builder, props);
this.alias(VelocityManager.class, "struts.velocity.manager.classname", builder, props);
this.alias(UrlRenderer.class, "struts.urlRenderer", builder, props);
this.alias(ActionValidatorManager.class, "struts.actionValidatorManager", builder, props);
this.alias(ValueStackFactory.class, "struts.valueStackFactory", builder, props);
this.alias(ReflectionProvider.class, "struts.reflectionProvider", builder, props);
this.alias(ReflectionContextFactory.class, "struts.reflectionContextFactory", builder, props);
this.alias(PatternMatcher.class, "struts.patternMatcher", builder, props);
this.alias(ContentTypeMatcher.class, "struts.contentTypeMatcher", builder, props);
this.alias(StaticContentLoader.class, "struts.staticContentLoader", builder, props);
this.alias(UnknownHandlerManager.class, "struts.unknownHandlerManager", builder, props);
this.alias(UrlHelper.class, "struts.view.urlHelper", builder, props);
this.alias(TextParser.class, "struts.expression.parser", builder, props);
this.alias(DispatcherErrorHandler.class, "struts.dispatcher.errorHandler", builder, props);
this.alias(ExcludedPatternsChecker.class, "struts.excludedPatterns.checker", builder, props, Scope.PROTOTYPE);
this.alias(AcceptedPatternsChecker.class, "struts.acceptedPatterns.checker", builder, props, Scope.PROTOTYPE);
this.switchDevMode(props);
this.convertIfExist(props, "struts.ognl.logMissingProperties", "logMissingProperties");
this.convertIfExist(props, "struts.ognl.enableExpressionCache", "enableOGNLExpressionCache");
this.convertIfExist(props, "struts.ognl.enableOGNLEvalExpression", "enableOGNLEvalExpression");
this.convertIfExist(props, "struts.ognl.allowStaticMethodAccess", "allowStaticMethodAccess");
this.convertIfExist(props, "struts.configuration.xml.reload", "reloadXmlConfiguration");
this.convertIfExist(props, "struts.excludedClasses", "ognlExcludedClasses");
this.convertIfExist(props, "struts.excludedPackageNamePatterns", "ognlExcludedPackageNamePatterns");
this.convertIfExist(props, "struts.excludedPackageNames", "ognlExcludedPackageNames");
this.convertIfExist(props, "struts.additional.excludedPatterns", "additionalExcludedPatterns");
this.convertIfExist(props, "struts.additional.acceptedPatterns", "additionalAcceptedPatterns");
this.convertIfExist(props, "struts.override.excludedPatterns", "overrideExcludedPatterns");
this.convertIfExist(props, "struts.override.acceptedPatterns", "overrideAcceptedPatterns");
}
private void switchDevMode(LocatableProperties props) {
if ("true".equalsIgnoreCase(props.getProperty("struts.devMode"))) {
if (props.getProperty("struts.i18n.reload") == null) {
props.setProperty("struts.i18n.reload", "true");
}
if (props.getProperty("struts.configuration.xml.reload") == null) {
props.setProperty("struts.configuration.xml.reload", "true");
}
if (props.getProperty("struts.freemarker.templatesCache.updateDelay") == null) {
props.setProperty("struts.freemarker.templatesCache.updateDelay", "0");
}
props.setProperty("devMode", "true");
} else {
props.setProperty("devMode", "false");
}
}
}
从字面意义上来看alias就是更名的意思,我们打开它的源码可以看到大概的功能就是:如果用户在配置<bean>的时候已经配置了上面提到的类如ObjectFactory则将其name改为“defult”,否则则会自动加载并且name为”default“。
protected void alias(Class type, String key, ContainerBuilder builder, Properties props) {
this.alias(type, key, builder, props, Scope.SINGLETON);
}
//以ObjectFactory为例,如果没有类型为 ObjectFactory.class,名字为“default”的bean,则需要通过以下操作将这个bean的name属性改为“default”
protected void alias(Class type, String key, ContainerBuilder builder, Properties props, Scope scope) {
if (!builder.contains(type, "default")) {
String foundName = props.getProperty(key, "struts");
if (builder.contains(type, foundName)) {//已经存在了ObjectFactory,则直接改名
LOG.trace("Choosing bean ({}) for ({})", foundName, type.getName());
builder.alias(type, foundName, "default");
} else {//不存在ObjectFactory则需要进行配置
try {
//加载ObjectFactory并注册到builder中
Class cls = ClassLoaderUtil.loadClass(foundName, this.getClass());
LOG.trace("Choosing bean ({}) for ({})", cls.getName(), type.getName());
builder.factory(type, cls, scope);
} catch (ClassNotFoundException var8) {
LOG.trace("Choosing bean ({}) for ({}) to be loaded from the ObjectFactory", foundName, type.getName());
if (!"struts".equals(foundName)) {
if (ObjectFactory.class == type) {
throw new ConfigurationException("Cannot locate the chosen ObjectFactory implementation: " + foundName);
}
builder.factory(type, new AbstractBeanSelectionProvider.ObjectFactoryDelegateFactory(foundName, type), scope);
}
}
}
} else {
//无法别名bean类型(),已分配默认映射。
LOG.warn("Unable to alias bean type ({}), default mapping already assigned.", type.getName());
}
}
关键的一句应该是:
//无法别名bean类型(),已分配默认映射。
LOG.warn("Unable to alias bean type ({}), default mapping already assigned.", type.getName());
对应的convertIfExist应该也是将根据struts.properties中已经存在的fromKey属性的值复制给新的toKey属性的值(可能是新旧版本之间的更替)。
protected void convertIfExist(LocatableProperties props, String fromKey, String toKey) {
if (props.containsKey(fromKey)) {//把名为fromKey的属性的值赋值给名为toKey的属性
props.setProperty(toKey, props.getProperty(fromKey));
}
}
第九步:创建container
Container container = this.init_PreloadConfiguration();
container.inject(this);
对于Container个人现在还很迷糊。本文篇幅也较长了,所以还是单独写一遍作为记录。
Next:Container