我们可以看到,在Container的默认实现,ContainerImpl中有两个实例变量。factoris和factoryNamesByType。
对象制造工厂
class ContainerImpl implements Container {
final Map<Key<?>, InternalFactory<?>> factories;
final Map<Class<?>, Set<String>> factoryNamesByType;
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是Key。
class Key<T> {
final Class<T> type;
final String name;
final int hashCode;
//...
}
看这个type与name是不是想起什么了?
对,就是struts-default.xml
<struts>
<bean class="com.opensymphony.xwork2.ObjectFactory" name="struts"/>
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="struts" class="org.apache.struts2.factory.StrutsResultFactory" />
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
<bean type="com.opensymphony.xwork2.factory.ConverterFactory" name="struts" class="com.opensymphony.xwork2.factory.DefaultConverterFactory" />
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="struts" class="org.apache.struts2.impl.StrutsActionProxyFactory"/>
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="prefix" class="org.apache.struts2.impl.PrefixBasedActionProxyFactory"/>
....
<struts>
type和name能唯一确认了一个bean。
再看看InternalFactory
interface InternalFactory<T> extends Serializable {
/**
* Creates an object to be injected.
*
* @param context of this injection
* @return instance to be injected
*/
T create(InternalContext context);
}
InternalFactory中存储了生成一个类的方法,而不是这个类的实例。
注入器
现在我们再看看注入器。
注入器是干什么的?
还记得上一篇我们说的人和车的例子么?
人只需要告诉容器,自己需要一辆车子,容器就会自动为人注入一辆车。
到底怎么自动的?注入器就是做这个事的。
咱们慢慢看。
ContainerImpl的inject方法如下所示。
//o就是人 人需要一辆车
void inject( Object o, InternalContext context ) {
//获得人身上的所有注入器
List<Injector> injectors = this.injectors.get(o.getClass()); //标识8
for ( Injector injector : injectors ) {
//调用注入器
injector.inject(context, o);
}
}
获得"人"上都有哪些注入器。
this.injectors.get(o.getClass());
在下面的例子中,人就有一个"方法注入器"
public class Person{
private Car car;
public Person(){
//其他代码
}
@Inject()
public void setCar(Car c){
this.car=c;
}
public void drive(){
car.drive();
}
}
注入器分两类,方法注入器,属性注入器。
其接口如下。
/**
* Injects a field or method in a given object.
*/
interface Injector extends Serializable {
void inject( InternalContext context, Object o );
}
我们看看属性注入器,方法注入器类似。
static class FieldInjector implements Injector {
final Field field;
final InternalFactory<?> factory;
final ExternalContext<?> externalContext;
public FieldInjector( ContainerImpl container, Field field, String name )
throws MissingDependencyException {
this.field = field;
...
}
Key<?> key = Key.newInstance(field.getType(), name);
factory = container.getFactory(key); //标识2
...
public void inject( InternalContext context, Object o ) {
ExternalContext<?> previous = context.getExternalContext();
context.setExternalContext(externalContext);
//省略trycatch
field.set(o, factory.create(context));//标识1
}
}
标识2 就是从容器里获得这个key的InternalFactory
在上面代码的标识1出,注入器做了最后的工作就是注入。
相信大家对InternalFactory的creat方法很好奇,到底是怎么实现的。
咱们不妨换个思路,field.set()的签名如下
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
如果对person p的字段Car c,及容器内部的Car c2来说,
它的调用就是
c.set(p,c2);
也就是说InternalFactory的creat就是产生了容器内的所托管的对象而已。
我们再看看ContainerImpl里injectors这个参数。
final Map<Class<?>, List<Injector>> injectors =
new ReferenceCache<Class<?>, List<Injector>>() {
@Override
protected List<Injector> create( Class<?> key ) { //标识7
List<Injector> injectors = new ArrayList<Injector>();
addInjectors(key, injectors); //标识4
return injectors;
}
};
怎么回事,看着好复杂呀。
public abstract class ReferenceCache<K, V> extends ReferenceMap<K, V> {
private static final long serialVersionUID = 0;
transient ConcurrentMap<Object, Future<V>> futures =
new ConcurrentHashMap<Object, Future<V>>();
transient ThreadLocal<Future<V>> localFuture = new ThreadLocal<Future<V>>();
protected abstract V create(K key);
//...
}
ReferenceMap实现了map接口。
有了ReferenceCatch,我们操作map就高效多了,当我们调用get方法时,如果key已经存在,就直接返回,否则就调用creat产生并缓存,下一次就不用再create了。
同时大家注意这个create是个抽象方法。
再换句话说,ContainerImpl中的injectors是在运行期动态构建的。
那么到底什么呢时候调用上面标识7处的creat方法呢?
在上面代码标识8处get后调用(ctrl+f 标识8)
这里牵扯到struts2的缓存技术,这边就先不讲了。
可参阅拙作
反正效果就是,当我们调用get方法时,如果key已经存在,就直接返回,否则就调用creat产生并缓存,下一次就不用再create了
好,接下来我们就看看标识4处的addInjectors方法。
void addInjectors( Class clazz, List<Injector> injectors ) {
if (clazz == Object.class) {
return;
}
// Add injectors for superclass first.
//英文看懂了吧, 先调用父类的
addInjectors(clazz.getSuperclass(), injectors);
// TODO (crazybob): Filter out overridden members.
addInjectorsForFields(clazz.getDeclaredFields(), false, injectors);
addInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
}
我们看看属性注入器。
void addInjectorsForFields( Field[] fields, boolean statics,
List<Injector> injectors ) {
addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
new InjectorFactory<Field>() {
//标识5
public Injector create( ContainerImpl container, Field field, String name ) throws MissingDependencyException {
return new FieldInjector(container, field, name);
}
});
}
在addInjectorsForFields里面,只有一行代码,就是调用addInjectorsForMembers,其参数的最后一个类型是InjectorFactory。
<M extends Member & AnnotatedElement> void addInjectorsForMembers(
List<M> members, boolean statics, List<Injector> injectors,
InjectorFactory<M> injectorFactory ) {
for ( M member : members ) {
if (isStatic(member) == statics) {
//看看这个member是否有Inject这个annotation
Inject inject = member.getAnnotation(Inject.class);
if (inject != null) {
try {
//这里调用injectorFactory了
//看上面代码的标识5
//就是产生一个injecter而已
injectors.add(injectorFactory.create(this, member, inject.value()));
} catch ( MissingDependencyException e ) {
if (inject.required()) {
throw new DependencyException(e);
}
}
}
}
}
}
如果大家再看看addInjectorsForMethods,只要我们在类的方法或成员变量上加上Inject这annotation,容器就会给参数注入一个相应的实例。
先看到这里吧,下一节我们再看XWork的实现机理。
(分析struts2的源码对我来说,还是很有难度的,文章写得不好,欢迎拍砖,共同进步)
感谢glt