我们可以看到,在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()); 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 ) { 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是在运行期动态构建的。
好,接下来我们就看看标识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