0
点赞
收藏
分享

微信扫一扫

XWork容器的存储结构


我们可以看到,在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的缓存技术,这边就先不讲了。

可参阅拙作

​​Struts2中的缓存---以Injector为例​​

反正效果就是,当我们调用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


举报

相关推荐

0 条评论