在上一篇struts2源码学习之初始化(二)中已经详细介绍了Dispatcher的初始化工作,只差最后一点,容器的创建。这一篇就仔细介绍容器的创建过程,初始化过程以及容器的作用。还是先从源码入手,上一篇已经分析到了Dispatcher类的init()的这段代码:
Container container = init_PreloadConfiguration();
container.inject(this);
init_CheckWebLogicWorkaround(container);
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;
}
先看ConfigurationManager类的getConfiguration()方法:
public synchronized Configuration getConfiguration() {
if (configuration == null) {
setConfiguration(createConfiguration(defaultFrameworkBeanName));
try {
configuration.reloadContainer(getContainerProviders());
} catch (ConfigurationException e) {
setConfiguration(null);
throw new ConfigurationException("Unable to load configuration.", e);
}
} else {
conditionalReload();
}
return configuration;
}
protected Configuration createConfiguration(String beanName) {
return new DefaultConfiguration(beanName);
}
public synchronized List reloadContainer(List providers) throws ConfigurationException {
packageContexts.clear();
loadedFileNames.clear();
List packageProviders = new ArrayList();
ContainerProperties props = new ContainerProperties();//封装配置文件中声明的常量
ContainerBuilder builder = new ContainerBuilder();
Container bootstrap = createBootstrapContainer(providers);
for (final ContainerProvider containerProvider : providers)
{
bootstrap.inject(containerProvider);
containerProvider.init(this);
containerProvider.register(builder, props);
}
props.setConstants(builder);
builder.factory(Configuration.class, new Factory() {
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
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 packageProviderNames = container.getInstanceNames(PackageProvider.class);
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;
}
ok,这个方法中可说的地方是在太多了,且听我细细道来。
1.ContainerBuilder类:
public final class ContainerBuilder {
final Map, InternalFactory>> factories =
new HashMap, InternalFactory>>();
final List> singletonFactories =
new ArrayList>();
final List> staticInjections = new ArrayList>();
private static final InternalFactory CONTAINER_FACTORY =
new InternalFactory() {
public Container create(InternalContext context) {
return context.getContainer();
}
};
private static final InternalFactory LOGGER_FACTORY =
new InternalFactory() {
public Logger create(InternalContext context) {
Member member = context.getExternalContext().getMember();
return member == null ? Logger.getAnonymousLogger()
: Logger.getLogger(member.getDeclaringClass().getName());
}
};
/**
* Constructs a new 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);
}
/**
* Maps a dependency. All methods in this class ultimately funnel through here.
*/
private ContainerBuilder factory(final Key key,
InternalFactory extends T> factory, Scope scope)
/**
* Convenience method. Equivalent to {@code alias(type, Container.DEFAULT_NAME, type)}.
*/
public ContainerBuilder alias(Class type, String alias)
/**
* Maps a constant value to the given name.
*/
public ContainerBuilder constant(String name, String value) {
return constant(String.class, name, value);
}
/**
* Upon creation, the {@link Container} will inject static fields and methods
* into the given classes.
*/
public ContainerBuilder injectStatics(Class>... types) {
staticInjections.addAll(Arrays.asList(types));
return this;
}
public Container create(boolean loadSingletons)
}
先说方法,factory()和alias()有多个重载方法,用于收集创建Container对象的参数,也就是在ContainerProvider的register()中调用factory()方法了。然后调用这里的create()创建出一个Container来。重点要说一下的是,这里所用到的建造者模式。
因为Container对象的创建需要读取多个配置文件的配置信息,然后才能创建出可用的对象,如果直接new的话,创建出来的对象是不可用的。所以这里巧妙地使用了建造者模式来创建Container对象,零散的收集工作分布于各个ContainerProvider的register()中,只要一一调用register()就可以开始创建Container了。更多的关于建造者模式的介绍可以参阅原型模式与创建者模型。
接下来要说的自然就是它的属性了。之前说过,Configuration类的Container属性将容器配置元素对象化了,而这些配置信息还是要暂时保存起来的,那么ContainerProvider类加载进来的配置信息保存在哪里呢?既然是通过ContainerBuilder类的factory()方法收集起来,自然也是保存在ContainerBuilder了。上面代码列出的factories属性和singletonFactories属性都是保存配置信息的。可以看到,factories是一个从Key到InternalFactory的Map,而singletonFactories则是一个保存InternalFactory的List。
接下来看看Key和InternalFactory为何物吧。
class Key {
final Class type;
final String name;
final int hashCode;
private Key(Class 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 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 Key newInstance(Class type, String name) {
return new Key(type, name);
}
}
好,看看InternalFactory,它被设计为接口:
interface InternalFactory extends Serializable {
/**
* Creates an object to be injected.
*
* @param context of this injection
* @return instance to be injected
*/
T create(InternalContext context);
}
最后看看ContainerBuilder类的构造方法,可以看到加了两个内置的bean,它们并不是配置文件中定义的,而是以编码的方式加入的。这是两个什么样的bean呢?望文生义吧。
2.DefaultConfiguration类的createBootstrapContainer()
看看它的实现:
protected Container createBootstrapContainer(List providers) {
ContainerBuilder builder = new ContainerBuilder();
boolean fmFactoryRegistered = false;
for (ContainerProvider provider : providers) {
if (provider instanceof FileManagerProvider) {
provider.register(builder, null);
}
if (provider instanceof FileManagerFactoryProvider) {
provider.register(builder, null);
fmFactoryRegistered = true;
}
}
builder.factory(ObjectFactory.class, Scope.SINGLETON);
builder.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON);
if (!fmFactoryRegistered) {
builder.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON);
}
builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
builder.factory(XWorkConverter.class, Scope.SINGLETON);
builder.factory(ConversionPropertiesProcessor.class, DefaultConversionPropertiesProcessor.class, Scope.SINGLETON);
builder.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON);
builder.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON);
builder.factory(TypeConverterCreator.class, DefaultTypeConverterCreator.class, Scope.SINGLETON);
builder.factory(TypeConverterHolder.class, DefaultTypeConverterHolder.class, Scope.SINGLETON);
builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
builder.factory(TypeConverter.class, XWorkConstants.COLLECTION_CONVERTER, CollectionConverter.class, Scope.SINGLETON);
builder.factory(TypeConverter.class, XWorkConstants.ARRAY_CONVERTER, ArrayConverter.class, Scope.SINGLETON);
builder.factory(TypeConverter.class, XWorkConstants.DATE_CONVERTER, DateConverter.class, Scope.SINGLETON);
builder.factory(TypeConverter.class, XWorkConstants.NUMBER_CONVERTER, NumberConverter.class, Scope.SINGLETON);
builder.factory(TypeConverter.class, XWorkConstants.STRING_CONVERTER, 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(XWorkConstants.DEV_MODE, "false");
builder.constant(XWorkConstants.LOG_MISSING_PROPERTIES, "false");
builder.constant(XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, "false");
builder.constant(XWorkConstants.RELOAD_XML_CONFIGURATION, "false");
return builder.create(true);
}
我们只看FileManagerProvider的register()方法实现即可。其他Provider的register()类似。
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
builder.factory(FileManager.class, name, fileManagerClass, Scope.SINGLETON);
}
public ContainerBuilder factory(final Class type, final String name,
final Class extends T> implementation, final Scope scope) {
// This factory creates new instances of the given implementation.
// We have to lazy load the constructor because the Container
// hasn't been created yet.
InternalFactory extends T> factory = new InternalFactory() {
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() {{
put("type", type);
put("name", name);
put("implementation", implementation);
put("scope", scope);
}}.toString();
}
};
return factory(Key.newInstance(type, name), factory, scope);
}
private ContainerBuilder factory(final Key key,
InternalFactory extends T> factory, Scope scope) {
ensureNotCreated();
checkKey(key);
final InternalFactory extends T> scopedFactory =
scope.scopeFactory(key.getType(), key.getName(), factory);
factories.put(key, scopedFactory);
if (scope == Scope.SINGLETON) {
singletonFactories.add(new InternalFactory() {
public T create(InternalContext context) {
try {
context.setExternalContext(ExternalContext.newInstance(
null, key, context.getContainerImpl()));
return scopedFactory.create(context);
} finally {
context.setExternalContext(null);
}
}
});
}
return this;
}
为什么要加入这么多的factory呢?后面说到Container的inject()就知道啦!
ok,收集完了配置信息,就可以调用create()创建出Container了。
3.ContainerBuilder的create():
欲知详情,且听下回分解。