码迷,mamicode.com
首页 > 其他好文 > 详细

XWork容器的存储结构

时间:2015-01-23 20:06:36      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:struts2   xwork   container   injector   referencecache   

我们可以看到,在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


XWork容器的存储结构

标签:struts2   xwork   container   injector   referencecache   

原文地址:http://blog.csdn.net/dlf123321/article/details/43059933

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!