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());
        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

时间: 2024-11-07 07:11:12

XWork容器的存储结构的相关文章

依据已有的条件分析了Docker的镜像与容器的存储结构

http://www.techbang.com/users/miss872misruls?=for http://www.techbang.com/users/miss851mislhqg http://www.techbang.com/users/miss547misdqxr http://www.techbang.com/users/miss576misxilr http://www.techbang.com/users/miss752miscuzx http://www.techbang.

Docker底层存储结构

Docker底层存储结构 由于aufs并未并入内核,故而目前只有Ubuntu系统上能够使用aufs作为docker的存储引擎,而其他系统上使用lvm thin provisioning(overlayfs是一个和aufs类似的union filesystem,未来有可能进入内核,但目前还没有:Lvm snapshot are useful for doing e.g. backup of a snapshot, but regress badly in performance when you

Oracle_高级功能(4) 数据库存储结构

数据库存储结构分为:物理存储结构和逻辑存储结构.物理结构和逻辑结构分开,对物理数据的存储不会影响对逻辑结构的访问.1.物理存储结构 数据库文件 os block2.逻辑存储结构 tablespace 表空间 segment 段 extend 扩展区 db block 数据块(8k)2.1创建表空间create tablespace <ts_name> datafile '<file>' size <n> reuse autoextend on next <n>

详解Oracle存储结构 掌握基本操作管理

2018.10.14那天我写了Oracle12C 的安装并初步了解了一下Oracle体系结构中数据库和实例.从中我们知道: 数据库是磁盘上数据的集合,位于收集和维护相关信息的数据库服务器上的一个或多个文件中.数据库由各种物理和逻辑结构组成,而表则是数据库中最重要的逻辑结构.表由包含数据的相关行和列组成. 组成数据库的文件主要分为两类:数据库文件和非数据库文件.两者之间的区别在于存储何种数据.数据库文件包含数据和元数据,非数据库文件则包含初始参数和日志记录信息等.数据库文件对于每时每刻正在进行的数

SQL SERVER大话存储结构(5)

阅读目录(Content) 1 基本介绍 2 对数据库启动的影响 3 日志文件添加方式 4 物理结构 5 延迟日志截断原因 6 管理事务日志 本系列上一篇博文链接:SQL SERVER大话存储结构(4)_复合索引与包含索引 回到顶部(go to top) 1 基本介绍 每个数据库都具有事务日志,用于记录所有事物以及每个事物对数据库所作的操作. 日志的记录形式需要根据数据库的恢复模式来确定,数据库恢复模式有三种: 完整模式,完全记录事物日志,需要定期进行日志备份. 大容量日志模式,适用于批量操作的

二叉树的链式存储结构----二叉链表

头文件:head.h #include<string.h> #include<ctype.h> #include<malloc.h> /* malloc()等 */ #include<limits.h> /* INT_MAX等 */ #include<stdio.h> /* EOF(=^Z或F6),NULL */ #include<stdlib.h> /* atoi() */ #include<io.h> /* eof()

SQLServer2012 表IAM存储结构探究

SQLServer2012 表IAM存储结构探究 Author:zfive5(zidong) Email: [email protected] 引子 国庆节期间,一直在翻阅<程序员的自我修养-链接.装载与库>,这本给我的感觉是越看越乱,但总的来说还不错,一句话--优秀程序员就应该知道每一个字节的意义. 看此书前的两本<深入解析SQLServer2008>和<Microsoft SQL Server 2005技术内幕:存储引擎>对IAM解读都是点到为止,让我满脑袋是一堆问

SQL SERVER大话存储结构(2)

阅读目录(Content) 1 行记录如何存储 1.1 堆表 1.2 聚集索引表格 2 非聚集索引结构 3 非聚集索引键值内容 3.1 堆表上的非聚集索引 3.2 聚集索引表(唯一)的非聚集索引 3.3 聚集索引表(非唯一)的非聚集索引 4 非聚集索引如何查找页 如果转载,请注明博文来源: www.cnblogs.com/xinysu/   ,版权归 博客园 苏家小萝卜 所有.望各位支持! 本系列上一篇博文链接:SQL SERVER大话存储结构(1)_数据页类型及页面指令分析 回到顶部(go t

SQL SERVER大话存储结构(3)

阅读目录(Content) 1 引入 2 数据行 2.1 数据行结构 2.2 特殊情况(大对象.行溢出及forword) 2.2.1 大对象 2.2.2 行溢出 2.2.3 forword 3 测试存储情况 3.1 堆表分析 3.2 添加主键 3.3 增加一列:可空变长列 3.4 增加一列:非空变长列+默认值 3.4.1 非大对象列 3.5 删除无数据的列 3.6 删除有数据的列 3.7 行溢出 3.8 Forword 4 行结构与DDL 一行数据是如何来存储的呢? 变长列与定长列,NULL与N