container是容器的意思,这让人很容易联想到java的Collection接口下的集合类,然而container并不是一个数据结构,我认为container其实是一个工厂,可以对对象的生命周期进行管理,,使对象的创建与业务逻辑的代码分开,同时可以避免对象的频繁的无用的创建,它可以将从配置文件中读取到的信息,通过依赖注入,缓存成key,value形式,也可以通过getInstance()通过反射将要调用的对象提取出来,,下面将对Container容器相关的类或接口的源码进行解析。
Container接口
从方法列表中可以大概看出整个容器的实现方式,依赖注入,getInstance获取instance。
下面我们来看看这个接口的实现类ContainerImpl
getInstance()方法
@SuppressWarnings("unchecked")
<T> T getInstance( Class<T> type, String name, InternalContext context ) {
ExternalContext<?> previous = context.getExternalContext();
Key<T> key = Key.newInstance(type, name);
context.setExternalContext(ExternalContext.newInstance(null, key, this));
try {
InternalFactory o = getFactory(key);
if (o != null) {
/*
*根据key获取相应的工厂,并且创建实例返回
*/
return getFactory(key).create(context);
} else {
return null;
}
} finally {
context.setExternalContext(previous);
}
}
从参数列表我们可以看出,这个方法获取的参数类型是类,名称,以及上下文,走进ExternalContext这个类,我们会发现,这个类实现了Context接口,而类和名称,发现与配置文件struts-dufault.xml中的bean节点的信息是一一对应的,由此我们可以推测,容器的加载,不仅仅为运行时的类提供服务,也负责加载配置文件中的信息,并将该类实例注入容器,而容器缓存的是创建实例的工厂,并不是实例本身。
下面我们来看一下ContainerImpl的构造方法
ContainerImpl( Map<Key<?>, InternalFactory<?>> factories ) {
this.factories = factories;
Map<Class<?>, Set<String>> map = new HashMap<Class<?>, Set<String>>();
for ( Key<?> key : factories.keySet() ) {
Set<String> names = map.get(key.getType());
if (names == null) {
names = new HashSet<String>();
map.put(key.getType(), names);
}
names.add(key.getName());
}
for ( Entry<Class<?>, Set<String>> entry : map.entrySet() ) {
entry.setValue(Collections.unmodifiableSet(entry.getValue()));
}
this.factoryNamesByType = Collections.unmodifiableMap(map);
}
构造方法内有两个参数,第一个是factories,是Map结构,由构造函数传递对象并缓存在内部,迭代时时所使用的类Key,进入其中发现,是以type为键,name为值,创建实例。第二个是factoryNamesByType,是可以通过name进行寻址的。
这些方法的主要作用是针对所有的方法或者属性查找满足条件的注入器,进行注入,并且缓存到injectors。
实际上container不止提供创建实例的工厂,还对这些数据进行了缓存,用于记录对象与对象之间的依赖关系。被称之为注入器(Injector)
ReferenceCache类是xwork对于缓存的一种实现
显然ReferenceCache缓存同样是通过键值对的形式进行存储,而且还加入了ThreadLocal模式,使得线程安全。
说到容器,不得不提到另一个加载各种配置文件的类,ObjectFactory,顾名思义,对象工厂。
这个类负责创建Action,Interceptor,Result,Validator等框架内部对象,以及buildBean()这个方法,这个方法可以将传入的对象实例化,内部是通过反射创建的。