3、所有需要解析的配置文件的解析類全部放入ConfigurationManager中的containerProviders中之後
1:Container container = init_PreloadConfiguration();
這段代碼,負責創建一個container對象,並初始化所有需要配置的文件信息;
首先,該方法屬於Dispatcher中的方法,該方法的主要內容如下:
/**
* 加載前進行的配置初始化
* @return
*/
private Container init_PreloadConfiguration() {
//獲取configuration
①Configuration config = configurationManager.getConfiguration();
//從configuration中獲取container的一個實例
②Container container = config.getContainer();
//獲取是否配置了國際化
③boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
//定義是否需要重新裝載資源綁定
④LocalizedTextUtil.setReloadBundles(reloadi18n);
return container;
}
①Configuration config = configurationManager.getConfiguration();
調用ConfigurationManager的getConfiguration()方法獲取一個Configuration的實例,該方法的主要內容如下:
/**
* 獲取當前的xwork配置類。順便一個DefaultConfiguration的實體對象將被返回
*/
public synchronized Configuration getConfiguration() {
//系統首次運行時,該對象爲空
if (configuration == null) {
//創建一個新的DefaultConfiguration對象,並用其初始化Configuration
setConfiguration(createConfiguration(defaultFrameworkBeanName));
try {
//調用DefaultConfiguration對象的reloadContainer方法;加載、解析所有配置文件
configuration.reloadContainer(getContainerProviders());
} catch (ConfigurationException e) {
setConfiguration(null);
throw new ConfigurationException("Unable to load configuration.", e);
}
} else {
//重新加載配置文件如果配置文件裏面指明要重新加載
conditionalReload(configuration.getContainer());
}
//返回這個configuration實例
return configuration;
}
代碼setConfiguration(createConfiguration(defaultFrameworkBeanName));
其中createConfiguration(defaultFrameworkBeanName)的具體代碼如下
/**
* 創建一個DefaultConfiguration對象
* @param beanName 此時beanName爲struts
* @return
*/
protected Configuration createConfiguration(String beanName) {
return new DefaultConfiguration(beanName);
}
在該方法裏,調用DefaultConfiguration的構造方法如下:
/**
* 構造方法,傳遞一個DefaultBeanName;
* 如果沒傳遞的話,默認設置爲xwork
* @param defaultBeanName
*/
public DefaultConfiguration(String defaultBeanName) {
this.defaultFrameworkBeanName = defaultBeanName;
}
在這裏設置了DefaultConfiguration的protected String defaultFrameworkBeanName;
上述createConfiguration(String beanName)返回了一個DefaultConfiguration的實例,
此時再調用ConfigurationManager中的setConfiguration把新實例化的DefaultConfiguration填充變量,該方法的具體代碼如下:
/**
* 通過傳遞過來的參數DefaultConfiguration初始化configuration
* @param configuration
*/
public synchronized void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
此時初始化
protected Configuration configuration;//這個變量爲DefaultConfiguration
然後調用實例化之後的configuration的reloadContainer(getContainerProviders())方法,在該方法內部負責對配置文件進行加載和解析
首先調用ConfigurationManager的getContainerProviders()返回containerProviders這個實例具體代碼如下
/**
* 獲取當前ConfigurationManager中包含的provider對象
* @return the list of registered ConfigurationProvider objects
* @see ConfigurationProvider
*/
public List<ContainerProvider> getContainerProviders() {
providerLock.lock();
try {
//理論上,不出意外的話,將直接返回containerProviders對象
if (containerProviders.size() == 0) {
containerProviders.add(new XWorkConfigurationProvider());//該類主要加載bean
containerProviders.add(new XmlConfigurationProvider("xwork.xml", false));//加載xwork配置解析provider
}
return containerProviders;
} finally {
providerLock.unlock();
}
}
此時返回containerProviders這個實例
然後調用configuration的reloadContainer(List<ContainerProvider> containerProviders)方法,在這個方法裏面,對所有的配置信息進行了解析該方法的具體內容如下:
/**
* @throws ConfigurationException
*/
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
1)packageContexts.clear();//清空packageContexts
2)loadedFileNames.clear();//清空loadedFileNames
3)List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();
4)ContainerProperties props = new ContainerProperties();//創建一個容器配置管理類,當前內部類
5)ContainerBuilder builder = new ContainerBuilder();//創建一個ContainerBuilder對象
6)Container bootstrap = createBootstrapContainer();//實例化一個Container對象,該對象是ContainerImpl的一個實例
//循環每一個ContainterProvider,將他們各自對應的容器配置元素註冊到ContainerBuilder中去,
//這裏,首先加載provider中的配置
for (final ContainerProvider containerProvider : providers)
{
//containerProvider進行依賴注入,這部分代碼放在後面的struts2的依賴注入進行介紹
7)bootstrap.inject(containerProvider);
//這裏對於資源文件的處理分兩步走
//當前的this指DefaultConfiguration這個對象
8)containerProvider.init(this);//第一步是初始化,即完成格式轉換,如xml格式的轉換爲 document對象集合.
//providers中存放的數據有以下內容:
/**
* 1、DefaultPropertiesProvider(default.properties),這個類的register運行結束之後,參數全部放入了props裏面
* 2、StrutsXmlConfigurationProvider(struts-defaults.xml);這個類中constant放入build中,bean放入props中
* 3、StrutsXmlConfigurationProvider(struts-plugin.xml);這個類中constant放入build中,bean放入props中
* 4、StrutsXmlConfigurationProvider(struts.xml);這個類中constatn放入build中,bean放入props中
* 5、LegacyPropertiesConfigurationProvider;這個類中需要配置的參數放入build中
* 6、加載用戶配置的文件,一般情況下,未添加
* 7、init_FilterInitParameters(添加在web.xml的Filter中配置的常量);把web.xml中的fileter中的參數放入props中
* 8、BeanSelectionProvider;把配置放入builder中的factories中
*/
9)containerProvider.register(builder, props);//第二步是將資源文件中配置的對象註冊到容器構造者對象中去。
}
//把props中的參數放入builder中
10)props.setConstants(builder);
//在builder中添加一個Configuration
11)builder.factory(Configuration.class, new Factory<Configuration>() {
public Configuration create(Context context) throws Exception {
return DefaultConfiguration.this;
}
});
//獲取當前線程的ActionContext
12)ActionContext oldContext = ActionContext.getContext();
try {
// Set the bootstrap container for the purposes of factory creation
13)setContext(bootstrap);
14)container = builder.create(false);
15)setContext(container);
16)objectFactory = container.getInstance(ObjectFactory.class);//獲取一個objectFactory實例
// Process the configuration providers first
// 首先執行providers配置
for (final ContainerProvider containerProvider : providers)
{
/**
* 解析xml中配置的package元素
*/
if (containerProvider instanceof PackageProvider) {
17)container.inject(containerProvider);//進行依賴注入,這部分代碼放在後面的struts2的依賴注入進行介紹
/**
* 1、DefaultPropertiesProvider(default.properties),這個類的loadPackages()方法不執行任何操作
* 2、StrutsXmlConfigurationProvider(struts-defaults.xml);這個類中的loadPackages()方法執行的結果解析了配置文件中的package元素並放入DefaultConfiguration元素的packageContexts中
* 3、StrutsXmlConfigurationProvider(struts-plugin.xml);這個類中的loadPackages()方法執行的結果解析了配置文件中的package元素並放入DefaultConfiguration元素的packageContexts中
* 4、StrutsXmlConfigurationProvider(struts.xml);這個類中的loadPackages()方法執行的結果解析了配置文件中的package元素並放入DefaultConfiguration元素的packageContexts中
* 5、LegacyPropertiesConfigurationProvider;這個類的loadPackages()方法不執行任何操作
* 6、加載用戶配置的文件,一般情況下,未添加
* 7、init_FilterInitParameters;這個類的loadPackages()方法不執行任何操作
* 8、BeanSelectionProvider;這個類的loadPackages()方法不執行任何操作
*/
18)((PackageProvider)containerProvider).loadPackages();//調用loadPackages方法
19)packageProviders.add((PackageProvider)containerProvider);
}
}
// Then process any package providers from the plugins
//讓後執行plugins中的package providers
20)Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);
if (packageProviderNames != null) {
for (String name : packageProviderNames) {
21)PackageProvider provider = container.getInstance(PackageProvider.class, name);
22)provider.init(this);
23)provider.loadPackages();
24)packageProviders.add(provider);
}
}
25)rebuildRuntimeConfiguration();
} finally {
if (oldContext == null) {
26)ActionContext.setContext(null);
}
}
27)return packageProviders;
}
1)packageContexts.clear();//清空packageContexts
該DefaultConfiguration中有
protected Map<String, PackageConfig> packageContexts = new LinkedHashMap<String, PackageConfig>();
這麼一個屬性在第一次加載時,先把這個屬性中的內容清空
map裏面的PackageConfig(com.opensymphony.xwork2.config.entities)這個類是一個package的配置類,該類在xml的配置文件中,相當於package標籤。該類的具體作用和用法將在下面講到
2)loadedFileNames.clear();//清空loadedFileNames,該參數用於記錄已經加載的文件名
該DefaultConfiguration中有
protected Set<String> loadedFileNames = new TreeSet<String>();這麼一個屬性。在第一次加載時,先把這個屬性中的內容清空
3)List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();
創建一個PackageProvider(com.opensymphony.xwork2.config)的list;該PackageProvider是一個接口,該接口的主要內容如下
public interface PackageProvider {
/**
* 初始化配置信息
* @param configuration The configuration
* @throws ConfigurationException If anything goes wrong
*/
public void init(Configuration configuration) throws ConfigurationException;
/**
* 告知該packageProvider是否需要重新加載
*
* @return <tt>true</tt>, whether the PackageProvider should reload its configuration, <tt>false</tt>otherwise.
*/
public boolean needsReload();
/**
* 爲配置加載該packageProvider
* @throws ConfigurationException
*/
public void loadPackages() throws ConfigurationException;
}
該接口定義了3個方法,分別爲init(Configuration configuration),needsReload(),loadPackages()
4)ContainerProperties props = new ContainerProperties();//創建一個容器配置管理類,當前內部類
創建一個ContainerProperties(當前DefaultConfiguration的內部類)的類,該類的主要代碼如下
/**
* 容器配置類
* 該類繼承自LoctableProperites
* @author Administrator
*
*/
class ContainerProperties extends LocatableProperties {
private static final long serialVersionUID = -7320625750836896089L;
@Override
public Object setProperty(String key, String value) {
String oldValue = getProperty(key);
if (LOG.isInfoEnabled() && oldValue != null && !oldValue.equals(value) && !defaultFrameworkBeanName.equals(oldValue)) {
LOG.info("Overriding property "+key+" - old value: "+oldValue+" new value: "+value);
}
return super.setProperty(key, value);
}
/**
* 把builder中的
* @param builder
*/
public void setConstants(ContainerBuilder builder) {
for (Object keyobj : keySet()) {
String key = (String)keyobj;
//這裏調用了builder的方法,將在後面進行介紹
builder.factory(String.class, key,
new LocatableConstantFactory<String>(getProperty(key), getPropertyLocation(key)));
}
}
}
該類繼承自LocatableProperties(com.opensymphony.xwork2.util.location)這個類繼承了Properties類,並實現了Locatable(com.opensymphony.xwork2.util.location)接口,
Locatable接口的主要內容如下:
public interface Locatable {
/**
* 得到這個對象的地址
* @return 返回對象創建的地址
*/
public Location getLocation();
}
5)ContainerBuilder builder = new ContainerBuilder();//創建一個ContainerBuilder對象
調用ContainerBuilder(com.opensymphony.xwork2.inject)的默認無參構造方法,該方法具體內容如下:
/**
* 創建一個新的builder.
*/
public ContainerBuilder() {
// 在當前容器中作爲默認容器的實現
factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME), CONTAINER_FACTORY);
// 注入的注入成員的日誌記錄
factories.put(Key.newInstance(Logger.class, Container.DEFAULT_NAME), LOGGER_FACTORY);
}
在該ContainerBuilder中有一個常量
final Map<Key<?>, InternalFactory<?>> factories = new HashMap<Key<?>, InternalFactory<?>>();
該常量是構建容器所必須的。其內容組成是與具體運行環境有關,既有來自struts2框架本身的配置所提供的一些組成部分,又有來自客戶項目的配置數據提供的組成部分
其中Key中包含的是類的類型,名稱和哈希值。InternalFactory代表的是生成類的工廠對象,調用其中的factory方法,就可以生成相應的對象
Key(com.opensymphony.xwork2.inject)該類的代碼如下:
/**
* 依賴映射的關鍵。所需的類型和名稱的唯一性標識。
*/
class Key<T> {
final Class<T> type;//類型
final String name;//名稱
final int hashCode;//哈希值
private Key(Class<T> type, String name) {
if (type == null) {
throw new NullPointerException("Type is null.");
}
if (name == null) {
throw new NullPointerException("Name is null.");
}
this.type = type;
this.name = name;
hashCode = type.hashCode() * 31 + name.hashCode();
}
Class<T> getType() {
return type;
}
String getName() {
return name;
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Key)) {
return false;
}
if (o == this) {
return true;
}
Key other = (Key) o;
return name.equals(other.name) && type.equals(other.type);
}
@Override
public String toString() {
return "[type=" + type.getName() + ", name='" + name + "']";
}
static <T> Key<T> newInstance(Class<T> type, String name) {
return new Key<T>(type, name);
}
}
InternalFactory(com.opensymphony.xwork2.inject)是一個接口,該接口的主要內容如下:
/**
* 創建將要被注入的對象的實例化工廠
*/
interface InternalFactory<T> extends Serializable {
/**
* 創建一個將要被注入的對象
*
* @param context of this injection
* @return instance 將要被注入的類的實例
*/
T create(InternalContext context);
}
InternalContext(com.opensymphony.xwork2.inject)該類用於協調和支持循環依賴注入;該類的代碼如下
/**
* 內部上下文。用於協調和支持循環依賴注入。
*/
class InternalContext {
final ContainerImpl container;
final Map<Object, ConstructionContext<?>> constructionContexts = new HashMap<Object, ConstructionContext<?>>();
Scope.Strategy scopeStrategy;
ExternalContext<?> externalContext;
InternalContext(ContainerImpl container) {
this.container = container;
}
public Container getContainer() {
return container;
}
ContainerImpl getContainerImpl() {
return container;
}
Scope.Strategy getScopeStrategy() {
if (scopeStrategy == null) {
scopeStrategy = (Scope.Strategy) container.localScopeStrategy.get();
if (scopeStrategy == null) {
throw new IllegalStateException("Scope strategy not set. "
+ "Please call Container.setScopeStrategy().");
}
}
return scopeStrategy;
}
@SuppressWarnings("unchecked")
<T> ConstructionContext<T> getConstructionContext(Object key) {
ConstructionContext<T> constructionContext =
(ConstructionContext<T>) constructionContexts.get(key);
if (constructionContext == null) {
constructionContext = new ConstructionContext<T>();
constructionContexts.put(key, constructionContext);
}
return constructionContext;
}
@SuppressWarnings("unchecked")
<T> ExternalContext<T> getExternalContext() {
return (ExternalContext<T>) externalContext;
}
void setExternalContext(ExternalContext<?> externalContext) {
this.externalContext = externalContext;
}
}
在創建ContainerBuilder的時候
factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME), CONTAINER_FACTORY);//在factories中添加一個創建Container的工廠
這行代碼,向factory中添加了一個記錄:Key.newInstance(Container.class, Container.DEFAULT_NAME)爲一個Key的實例。其中Container.DEFAULT_NAME爲default
CONTAINER_FACTORY(爲Container創建了一個工廠)爲:
private static final InternalFactory<Container> CONTAINER_FACTORY = new InternalFactory<Container>() {
public Container create(InternalContext context) {
return context.getContainer();
}
};
factories.put(Key.newInstance(Logger.class, Container.DEFAULT_NAME), LOGGER_FACTORY);//在factories中添加一個創建Logger的工廠
LOGGER_FACTORY(爲Logger創建一個工廠)爲:
private static final InternalFactory<Logger> LOGGER_FACTORY = new InternalFactory<Logger>() {
public Logger create(InternalContext context) {
Member member = context.getExternalContext().getMember();//(未分析)
return member == null ? Logger.getAnonymousLogger() : Logger.getLogger(member.getDeclaringClass().getName());(未分析)
}
};
6)Container bootstrap = createBootstrapContainer();//實例化一個Container對象,該對象是ContainerImpl的一個實例
在這裏首先創建一個ContainerBuilder,利用該對象中的方法,初始化factories讓後再創建一個ContainerImpl返回
該方法屬於DefaultConfiguration中的方法,其主要作用是創建一個Container對象。其代碼如下:
/**
* 創建一個Container對象
* @return
*/
protected Container createBootstrapContainer() {
/**
* 首先生成一個ContainerBuilder對象,調用register來實現對builder
* 對象的factories成員變量的設置
*/
ContainerBuilder builder = new ContainerBuilder();
/**
* 對框架的擴展點的實現,完成框架功能必須,因此也需要加載,否則容器無法正常起效,
* 以下這些擴展點暫時未分析
*/
//ObjectFactory負責創建核心框架對象
builder.factory(ObjectFactory.class, Scope.SINGLETON);
//其中FileManager訪問文件系統和文件的變化進行監測的基本接口
//DefaultFileManager是FileManager接口的實現類
builder.factory(FileManager.class, DefaultFileManager.class, Scope.SINGLETON);
//未分析
builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
//ValueStackFactory值棧類接口,OgnlValueStackFactory值棧的實現類
builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
//xwork的類型轉換器
builder.factory(XWorkConverter.class, Scope.SINGLETON);
//xwork的類型轉換器
builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
//Collection類型轉換器
builder.factory(TypeConverter.class, "collection", CollectionConverter.class, Scope.SINGLETON);
//Array類型轉換器
builder.factory(TypeConverter.class, "array", ArrayConverter.class, Scope.SINGLETON);
//Date類型轉換器
builder.factory(TypeConverter.class, "date", DateConverter.class, Scope.SINGLETON);
//Number類型轉換器
builder.factory(TypeConverter.class, "number", NumberConverter.class, Scope.SINGLETON);
//String類型轉換器
builder.factory(TypeConverter.class, "string", StringConverter.class, Scope.SINGLETON);
//文本類型轉換器
builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON);
builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
builder.factory(OgnlUtil.class, Scope.SINGLETON);
builder.constant("devMode", "false");
builder.constant("logMissingProperties", "false");
/**
* 參數收集完成,通過create實現容器的創建
*/
return builder.create(true);
}
在這個方法裏面涉及到ContainerBuilder的很多方法下面來對這些代碼進行分析:
public final class ContainerBuilder {
/**
*
* factories是構建容器所必須的,但其內容組成是與具體運行環境有關,既有來自struts2框架本身的
* 配置所提供的一些組成部分,又有來自客戶項目的配置數據提供的組成部分
* 構造容器對象的時候的參數是一個個的鍵值對,
* Key中包含的是類的類型,名稱和哈希值
* InternalFactory代表的是生成類的工廠對象,調用其中的factory方法,就可以生成相應的對象
*/
final Map<Key<?>, InternalFactory<?>> factories = new HashMap<Key<?>, InternalFactory<?>>();
/**
* 創建將要被注入的單例模式對象的列表
*/
final List<InternalFactory<?>> singletonFactories = new ArrayList<InternalFactory<?>>();
final List<Class<?>> staticInjections = new ArrayList<Class<?>>();
boolean created;//是否已被創建
boolean allowDuplicates = false;
//container_factory
private static final InternalFactory<Container> CONTAINER_FACTORY = new InternalFactory<Container>() {
public Container create(InternalContext context) {
return context.getContainer();
}
};
//logger_factory
private static final InternalFactory<Logger> LOGGER_FACTORY = new InternalFactory<Logger>() {
public Logger create(InternalContext context) {
Member member = context.getExternalContext().getMember();
return member == null ? Logger.getAnonymousLogger() : Logger.getLogger(member.getDeclaringClass().getName());
}
};
/**
* 創建一個新的builder.
*/
public ContainerBuilder() {
// 在當前容器中作爲默認容器的實現
factories.put(Key.newInstance(Container.class, Container.DEFAULT_NAME), CONTAINER_FACTORY);
// 注入的注入成員的日誌記錄
factories.put(Key.newInstance(Logger.class, Container.DEFAULT_NAME), LOGGER_FACTORY);
}
/**
* 實現功能的主體。其它的factory方法主要是用來進行參數的適配和改造。
*/
private <T> ContainerBuilder factory(final Key<T> key, InternalFactory<? extends T> factory, Scope scope) {
ensureNotCreated();//用來確定該容器是否已經創建
checkKey(key);//確認一個key是否已經映射了
final InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory);//對工廠類的作用範圍進行包裝
factories.put(key, scopedFactory);//把該工廠類放入factories中
//如果該工廠類的作用範圍爲singleton
if (scope == Scope.SINGLETON) {
//把該工廠類進行裝飾,放入單例模式對象的列表
singletonFactories.add(new InternalFactory<T>() {
public T create(InternalContext context) {
try {
context.setExternalContext(ExternalContext.newInstance(null, key, context.getContainerImpl()));
return scopedFactory.create(context);
} finally {
context.setExternalContext(null);
}
}
});
}
return this;
}
/**
* 確定一個key是否已經映射了
*/
private void checkKey(Key<?> key) {
if (factories.containsKey(key) && !allowDuplicates) {
throw new DependencyException("Dependency mapping for " + key + " already exists.");
}
}
/**
* 映射一個factory通過給定的依賴類型和名稱
*
* @param type of dependency
* @param name of dependency
* @param factory creates objects to inject
* @param scope scope of injected instances
* @return this builder
*/
public <T> ContainerBuilder factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope) {
/**
* 對傳入的factory對象進行裝飾
*/
InternalFactory<T> internalFactory = new InternalFactory<T>() {
public T create(InternalContext context) {
try {
Context externalContext = context.getExternalContext();
return factory.create(externalContext);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return new LinkedHashMap<String, Object>() {{
put("type", type);
put("name", name);
put("factory", factory);
}}.toString();
}
};
return factory(Key.newInstance(type, name), internalFactory, scope);
}
/**
* 相當於調用factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope);
*/
public <T> ContainerBuilder factory(Class<T> type, Factory<? extends T> factory, Scope scope) {
return factory(type, Container.DEFAULT_NAME, factory, scope);
}
/**
* 相當於調用factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope);
*/
public <T> ContainerBuilder factory(Class<T> type, String name, Factory<? extends T> factory) {
return factory(type, name, factory, Scope.DEFAULT);
}
/**
* 相當於調用factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope);
*/
public <T> ContainerBuilder factory(Class<T> type, Factory<? extends T> factory) {
return factory(type, Container.DEFAULT_NAME, factory, Scope.DEFAULT);
}
/**
* 映射一個給定依賴名字和類型的實現類,用container創建一個實例,遞歸依賴注入
* @param type 依賴的類型
* @param name 依賴的名稱
* @param implementation 實現類
* @param scope 注入的作用範圍
* @return this builder
*/
public <T> ContainerBuilder factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope) {
// 這個工廠創建一個給定實現類的實例
//對給定的implementation進行裝飾
InternalFactory<? extends T> factory = new InternalFactory<T>() {
volatile ContainerImpl.ConstructorInjector<? extends T> constructor;
@SuppressWarnings("unchecked")
public T create(InternalContext context) {
if (constructor == null) {
this.constructor =
context.getContainerImpl().getConstructor(implementation);
}
return (T) constructor.construct(context, type);
}
@Override
public String toString() {
return new LinkedHashMap<String, Object>() {{
put("type", type);
put("name", name);
put("implementation", implementation);
put("scope", scope);
}}.toString();
}
};
return factory(Key.newInstance(type, name), factory, scope);
}
/**
* 映射一個給定依賴名字和類型的實現類,用container創建一個實例,遞歸依賴注入
* <p>Sets scope to value from {@link Scoped} annotation on the
* implementation class. Defaults to {@link Scope#DEFAULT} if no annotation
* is found.
*
* @param type of dependency
* @param name of dependency
* @param implementation class
* @return this builder
*/
public <T> ContainerBuilder factory(final Class<T> type, String name, final Class<? extends T> implementation) {
Scoped scoped = implementation.getAnnotation(Scoped.class);
Scope scope = scoped == null ? Scope.DEFAULT : scoped.value();
return factory(type, name, implementation, scope);
}
/**
* 相當於調用 factory(final Class<T> type, String name, final Class<? extends T> implementation)
*/
public <T> ContainerBuilder factory(Class<T> type, Class<? extends T> implementation) {
return factory(type, Container.DEFAULT_NAME, implementation);
}
/**
* 相當於調用 factory(final Class<T> type, String name, final Class<? extends T> implementation)
*/
public <T> ContainerBuilder factory(Class<T> type) {
return factory(type, Container.DEFAULT_NAME, type);
}
/**
* 相當於調用 factory(final Class<T> type, String name, final Class<? extends T> implementation)
*/
public <T> ContainerBuilder factory(Class<T> type, String name) {
return factory(type, name, type);
}
/**
* 相當於調用factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope)
*/
public <T> ContainerBuilder factory(Class<T> type, Class<? extends T> implementation, Scope scope) {
return factory(type, Container.DEFAULT_NAME, implementation, scope);
}
/**
* 相當於調用factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope)
*/
public <T> ContainerBuilder factory(Class<T> type, Scope scope) {
return factory(type, Container.DEFAULT_NAME, type, scope);
}
/**
* 相當於調用factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope)
*/
public <T> ContainerBuilder factory(Class<T> type, String name, Scope scope) {
return factory(type, name, type, scope);
}
/**
* 相當於調用alias(Class<T> type, String alias)
*/
public <T> ContainerBuilder alias(Class<T> type, String alias) {
return alias(type, Container.DEFAULT_NAME, alias);
}
/**
* 映射一個已存在的工廠一個新的名字
*
* @param type of dependency
* @param name of dependency
* @param alias of to the dependency
* @return this builder
*/
public <T> ContainerBuilder alias(Class<T> type, String name, String alias) {
return alias(Key.newInstance(type, name), Key.newInstance(type, alias));
}
/**
* 映射一個現有的依賴關係。並替換key爲aliasKey
*/
private <T> ContainerBuilder alias(final Key<T> key, final Key<T> aliasKey) {
ensureNotCreated();//判斷該容器是否已經被創建
checkKey(aliasKey);//判斷該key是否已經存在
//獲取factories中指定key的對象
final InternalFactory<? extends T> scopedFactory = (InternalFactory<? extends T>)factories.get(key);
//如果該對象不存在,拋出異常
if (scopedFactory == null) {
throw new DependencyException("Dependency mapping for " + key + " doesn't exists.");
}
//把新的key,和對象放入aliasKey中
factories.put(aliasKey, scopedFactory);
return this;
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, String value) {
return constant(String.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, int value) {
return constant(int.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, long value) {
return constant(long.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, boolean value) {
return constant(boolean.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, double value) {
return constant(double.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, float value) {
return constant(float.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, short value) {
return constant(short.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, char value) {
return constant(char.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public ContainerBuilder constant(String name, Class value) {
return constant(Class.class, name, value);
}
/**
* 映射一個給定名稱的常量值
*/
public <E extends Enum<E>> ContainerBuilder constant(String name, E value) {
return constant(value.getDeclaringClass(), name, value);
}
/**
* 映射一個給定名稱和類型的常量值.
*/
private <T> ContainerBuilder constant(final Class<T> type, final String name, final T value) {
//對給定值進行裝飾
InternalFactory<T> factory = new InternalFactory<T>() {
public T create(InternalContext ignored) {
return value;
}
@Override
public String toString() {
return new LinkedHashMap<String, Object>() {
{
put("type", type);
put("name", name);
put("value", value);
}
}.toString();
}
};
return factory(Key.newInstance(type, name), factory, Scope.DEFAULT);
}
/**
* 在創建時,容器將注入靜態域和方法爲給定的類。
* @param types 將被注入的靜態常量成員
*/
public ContainerBuilder injectStatics(Class<?>... types) {
staticInjections.addAll(Arrays.asList(types));
return this;
}
/**
* 如果factories中包含給定類型和名稱的值,則返回true
*/
public boolean contains(Class<?> type, String name) {
return factories.containsKey(Key.newInstance(type, name));
}
/**
* 相當於調用contains(Class<?> type, String name)
*/
public boolean contains(Class<?> type) {
return contains(type, Container.DEFAULT_NAME);
}
/**
* Creates a {@link Container} instance. Injects static members for classes
* which were registered using {@link #injectStatics(Class...)}.
* 創建一個Container實例。
*
* @param loadSingletons 如果 boolean created(loadSingletons)值爲true 的話,先調用scope="singleton" 的對象工廠的create方法
* @throws IllegalStateException if called more than once
*/
public Container create(boolean loadSingletons) {
ensureNotCreated();//判斷是否已經創建
created = true;//設置created爲true
final ContainerImpl container = new ContainerImpl(new HashMap<Key<?>, InternalFactory<?>>(factories));
//把對象生命週期爲單實例的對象先創建出來.
if (loadSingletons) {
container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
public Void call(InternalContext context) {
for (InternalFactory<?> factory : singletonFactories) {
factory.create(context);
}
return null;
}
});
}
//依賴注入
container.injectStatics(staticInjections);
//返回一個ContainerImpl實例對象
return container;
}
/**
* 現在我們只支持創造每一容器實例生成器。
* 如果我們想支持創建每建造多個容器,我們要搬到一個“工廠”的模式,我們創建每個集裝箱廠實例。
* 現在,一個工廠的實例將在所有容器共享,單身人士對容器時延遲加載,等。
*/
private void ensureNotCreated() {
if (created) {
throw new IllegalStateException("Container already created.");
}
}
public void setAllowDuplicates(boolean val) {
allowDuplicates = val;
}
/**
* Implemented by classes which participate in building a container.
*/
public interface Command {
/**
* Contributes factories to the given builder.
*
* @param builder
*/
void build(ContainerBuilder builder);
}
}
7)bootstrap.inject(containerProvider);
containerProvider進行依賴注入,這部分代碼放在後面的struts2的依賴注入進行介紹
8)containerProvider.init(this);//這裏是比較核心的一個模塊
首先確定當前的providers中有哪些記錄
1:DefaultPropertiesProvider(default.properties)
執行DefaultPropertiesProvider該類的init(Configuration configuration)方法
該類的該方法如下:
/**
* 不用把該對象轉換成document對象
*/
public void init(Configuration configuration) throws ConfigurationException {
}
2:StrutsXmlConfigurationProvider(struts-default.xml)
該類沒有對init方法進行重寫,因此調用父類(XmlConfigurationProvider)的init方法
/**
* @param configuration 爲DefaultConfiguration對象的一個實例
*/
public void init(Configuration configuration) {
this.configuration = configuration;//設置configuration
this.includedFileNames = configuration.getLoadedFileNames();//此時爲空
loadDocuments(configFileName);//第一次爲loadDocuments(struts-defaults.xml)
}
/**
* @param configFileName struts-default.xml
*/
private void loadDocuments(String configFileName) {
try {
loadedFileUrls.clear();
documents = loadConfigurationFiles(configFileName, null);//把*.xml轉換成document形式,並存放到documents中
} catch (ConfigurationException e) {
throw e;
} catch (Exception e) {
throw new ConfigurationException("Error loading configuration file " + configFileName, e);
}
}
其中private Set<String> loadedFileUrls = new HashSet<String>();//已經加載的file的URL
/**
* 返回*.xml的document形式結果
* @param fileName struts-default.xml
* @param includeElement null
*/
private List<Document> loadConfigurationFiles(String fileName, Element includeElement) {
List<Document> docs = new ArrayList<Document>();//創建一個新的List<dom>對象
List<Document> finalDocs = new ArrayList<Document>();//再創建一個finalDocs的List<dom>對象
if (!includedFileNames.contains(fileName)) {//如果includedFileNames不包含名爲fileName的對象
if (LOG.isDebugEnabled()) {
LOG.debug("Loading action configurations from: " + fileName);
}
//把該fileName添加到includedFileNames,防止重複添加
includedFileNames.add(fileName);
Iterator<URL> urls = null;
InputStream is = null;
IOException ioException = null;
try {
/**
* 獲取fileName的URL
*/
urls = getConfigurationUrls(fileName);
} catch (IOException ex) {
ioException = ex;
}
/**
* 如果urls爲空,或urls.hasNext = true,則執行下面的代碼
*/
if (urls == null || !urls.hasNext()) {
if (errorIfMissing) {
throw new ConfigurationException("Could not open files of the name " + fileName, ioException);
} else {
if (LOG.isInfoEnabled()) {
LOG.info("Unable to locate configuration files of the name "
+ fileName + ", skipping");
}
return docs;//此時docs對象爲空
}
}
//否則
URL url = null;
while (urls.hasNext()) {
try {
//把fileName的URL傳遞給url
url = urls.next();
//fileManager對象爲DefaultFileManager,通過struts框架自動注入進來
//根據URL加載指定的文件,並返回inputStream形式的結果
is = fileManager.loadFile(url);
InputSource in = new InputSource(is);
//設置此輸入源的系統標識符
in.setSystemId(url.toString());
/**
* 在docs中添加一個document
*/
docs.add(DomHelper.parse(in, dtdMappings));
} catch (XWorkException e) {
if (includeElement != null) {
throw new ConfigurationException("Unable to load " + url, e, includeElement);
} else {
throw new ConfigurationException("Unable to load " + url, e);
}
} catch (Exception e) {
final String s = "Caught exception while loading file " + fileName;
throw new ConfigurationException(s, e, includeElement);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
LOG.error("Unable to close input stream", e);
}
}
}
}
//對documents進行排序,通過order這個屬性
Collections.sort(docs, new Comparator<Document>() {//(未分析)
public int compare(Document doc1, Document doc2) {
return XmlHelper.getLoadOrder(doc1).compareTo(XmlHelper.getLoadOrder(doc2));
}
});
/**
* 對docs中的內容進行遍歷
*/
for (Document doc : docs) {
Element rootElement = doc.getDocumentElement();
NodeList children = rootElement.getChildNodes();
int childSize = children.getLength();//struts-default.xml中有72個child;
//對xml進行解析,查看其所有子元素中是否包含include元素
for (int i = 0; i < childSize; i++) {
Node childNode = children.item(i);
if (childNode instanceof Element) {
//獲取element
Element child = (Element) childNode;
//獲取element的name
final String nodeName = child.getNodeName();
//如果element==include
if ("include".equals(nodeName)) {
String includeFileName = child.getAttribute("file");
if (includeFileName.indexOf('*') != -1) {
// handleWildCardIncludes(includeFileName, docs, child);
ClassPathFinder wildcardFinder = new ClassPathFinder();
wildcardFinder.setPattern(includeFileName);
Vector<String> wildcardMatches = wildcardFinder.findMatches();
for (String match : wildcardMatches) {
finalDocs.addAll(loadConfigurationFiles(match, child));
}
} else {
finalDocs.addAll(loadConfigurationFiles(includeFileName, child));//遞歸調用,把所有include加載到finalDocs
}
}
}
}
finalDocs.add(doc);
loadedFileUrls.add(url.toString());
}
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded action configuration from: " + fileName);
}
}
return finalDocs;
}
/**
* 獲取fileName的Iterator<URL>
* @param fileName
* @return
* @throws IOException
*/
protected Iterator<URL> getConfigurationUrls(String fileName) throws IOException {
return ClassLoaderUtil.getResources(fileName, XmlConfigurationProvider.class, false);
}
至此,struts-default.xml已經轉換成一個document對象放入docs中,接下來調用register再對轉換好的docs中的內容進行解析
3:StrutsXmlConfigurationProvider(struts-plugin.xml)
同2:
4:StrutsXmlConfigurationProvider(struts.xml)
同2:
5:LegacyPropertiesConfigurationProvider
該類的register中的代碼具體如下:
/**
* 註冊參數,把需要配置的參數放入builder對象的factories中
*/
@SuppressWarnings("unchecked")
public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {
//獲取一個Settings的實例
final Settings settings = Settings.getInstance();
loadSettings(props, settings);
// Set default locale by lazily resolving the locale property as needed into a Locale object
builder.factory(Locale.class, new Factory() {
private Locale locale;
public synchronized Object create(Context context) throws Exception {
if (locale == null) {
String loc = context.getContainer().getInstance(String.class, StrutsConstants.STRUTS_LOCALE);
if (loc != null) {
StringTokenizer localeTokens = new StringTokenizer(loc, "_");
String lang = null;
String country = null;
if (localeTokens.hasMoreTokens()) {
lang = localeTokens.nextToken();
}
if (localeTokens.hasMoreTokens()) {
country = localeTokens.nextToken();
}
locale = new Locale(lang, country);
} else {
if (LOG.isInfoEnabled()) {
LOG.info("No locale define, substituting the default VM locale");
}
locale = Locale.getDefault();
}
}
return locale;
}
});
}
6:用戶配置
具體代碼具體分析
7:web.xml的filter中配置的參數
//把web.xml中配置的fileter中的參數放入props中
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
props.putAll(initParams);
}
8:BeanSelectionProvider
該類內部的register方法如下:
/**
* 註冊
*/
public void register(ContainerBuilder builder, LocatableProperties props) {
/**
* 把這些配置放入builder的factories中
*/
alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props);
alias(FileManager.class, StrutsConstants.STRUTS_FILEMANAGER, builder, props);
alias(XWorkConverter.class, StrutsConstants.STRUTS_XWORKCONVERTER, builder, props);
alias(TextProvider.class, StrutsConstants.STRUTS_XWORKTEXTPROVIDER, builder, props, Scope.DEFAULT);
alias(ActionProxyFactory.class, StrutsConstants.STRUTS_ACTIONPROXYFACTORY, builder, props);
alias(ObjectTypeDeterminer.class, StrutsConstants.STRUTS_OBJECTTYPEDETERMINER, builder, props);
alias(ActionMapper.class, StrutsConstants.STRUTS_MAPPER_CLASS, builder, props);
alias(MultiPartRequest.class, StrutsConstants.STRUTS_MULTIPART_PARSER, builder, props, Scope.DEFAULT);
alias(FreemarkerManager.class, StrutsConstants.STRUTS_FREEMARKER_MANAGER_CLASSNAME, builder, props);
alias(VelocityManager.class, StrutsConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME, builder, props);
alias(UrlRenderer.class, StrutsConstants.STRUTS_URL_RENDERER, builder, props);
alias(ActionValidatorManager.class, StrutsConstants.STRUTS_ACTIONVALIDATORMANAGER, builder, props);
alias(ValueStackFactory.class, StrutsConstants.STRUTS_VALUESTACKFACTORY, builder, props);
alias(ReflectionProvider.class, StrutsConstants.STRUTS_REFLECTIONPROVIDER, builder, props);
alias(ReflectionContextFactory.class, StrutsConstants.STRUTS_REFLECTIONCONTEXTFACTORY, builder, props);
alias(PatternMatcher.class, StrutsConstants.STRUTS_PATTERNMATCHER, builder, props);
alias(StaticContentLoader.class, StrutsConstants.STRUTS_STATIC_CONTENT_LOADER, builder, props);
alias(UnknownHandlerManager.class, StrutsConstants.STRUTS_UNKNOWN_HANDLER_MANAGER, builder, props);
alias(UrlHelper.class, StrutsConstants.STRUTS_URL_HELPER, builder, props);
/**
* 判斷props中的devMode是否爲true
*/
if ("true".equalsIgnoreCase(props.getProperty(StrutsConstants.STRUTS_DEVMODE))) {
//設置國際化
props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, "true");
props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "true");
props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE, "false");
props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY, "0");
// Convert struts properties into ones that xwork expects
props.setProperty("devMode", "true");
} else {
props.setProperty("devMode", "false");
}
//把struts2的properties轉換成xwork的properties
convertIfExist(props, StrutsConstants.STRUTS_LOG_MISSING_PROPERTIES, "logMissingProperties");
convertIfExist(props, StrutsConstants.STRUTS_ENABLE_OGNL_EXPRESSION_CACHE, "enableOGNLExpressionCache");
convertIfExist(props, StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "allowStaticMethodAccess");
LocalizedTextUtil.addDefaultResourceBundle("org/apache/struts2/struts-messages");
//加載用戶資源綁定
loadCustomResourceBundles(props);
}
在這個方法內部調用了該類的alias方法,該方法具體如下:
/**
* 調用該類的alias(Class type, String key, ContainerBuilder builder, Properties props, Scope scope)方法,同時傳遞scope爲single
* @param type
* @param key
* @param builder
* @param props
*/
void alias(Class type, String key, ContainerBuilder builder, Properties props) {
alias(type, key, builder, props, Scope.SINGLETON);
}
接着調用另一個alias方法,該方法具體如下:
/**
* 把參數放入builder中
* @param type class類型
* @param key
* @param builder
* @param props
* @param scope
*/
void alias(Class type, String key, ContainerBuilder builder, Properties props, Scope scope) {
//判斷builder中是否存在指定type的參數
if (!builder.contains(type)) {
/**
* 從props中獲取指定key和默認值的字符串
*/
String foundName = props.getProperty(key, DEFAULT_BEAN_NAME);
//檢測builder中是否包含該type和指定默認值的配置
if (builder.contains(type, foundName)) {
if (LOG.isInfoEnabled()) {
LOG.info("Choosing bean (#0) for (#1)", foundName, type.getName());
}
//重新加載到builder中
builder.alias(type, foundName, Container.DEFAULT_NAME);
} else {
try {
//反射生成class
Class cls = ClassLoaderUtil.loadClass(foundName, this.getClass());
if (LOG.isDebugEnabled()) {
LOG.debug("Choosing bean (#0) for (#1)", cls.getName(), type.getName());
}
//把cls添加到builder中的factories中
builder.factory(type, cls, scope);
} catch (ClassNotFoundException ex) {
// Perhaps a spring bean id, so we'll delegate to the object factory at runtime
if (LOG.isDebugEnabled()) {
LOG.debug("Choosing bean (#0) for (#1) to be loaded from the ObjectFactory", foundName, type.getName());
}
if (DEFAULT_BEAN_NAME.equals(foundName)) {
// Probably an optional bean, will ignore
} else {
if (ObjectFactory.class != type) {
builder.factory(type, new ObjectFactoryDelegateFactory(foundName, type), scope);
} else {
throw new ConfigurationException("Cannot locate the chosen ObjectFactory implementation: " + foundName);
}
}
}
}
} else {
if (LOG.isWarnEnabled()) {
LOG.warn("Unable to alias bean type (#0), default mapping already assigned.", type.getName());
}
}
}
ContainerBuilder的代碼在上面已經給出了分析,因此在這裏不對其方法再次進行介紹。
10)props.setConstants(builder);
調用ContainerProperties的setConstants(ContainerBuilder builder)方法,把props中的信息放入ContainerBuilder的factories中;具體代碼在上面已經展示過了
11)這行代碼調用了ContainerBuilder的factory方法,向其factories中添加了一個Configuration的工廠類,該類的實例化爲一個DefaultConfiguration對象
builder.factory(Configuration.class, new Factory<Configuration>() {
public Configuration create(Context context) throws Exception {
return DefaultConfiguration.this;
}
});