struts2_源码学习_Container

续 Dispatcher(1) 

(PS:我终于搞明白 一点了 T-T  参考文章:https://www.cnblogs.com/huashui/p/3191886.html

目录

Container接口

对象的注入依赖

对象注入的实例

获取对象实例 


Container接口

package com.opensymphony.xwork2.inject;

public interface Container extends Serializable {
    //默认对象识别标志
    String DEFAULT_NAME = "default";
    //进行对象的依赖注入操作。o为被注入对象的对象。意思就是完成o中@inject操作
    void inject(Object var1);
    //创建一个类的实例并进行对象的依赖注入操作
    <T> T inject(Class<T> var1);
    //通过type和name获得实例
    <T> T getInstance(Class<T> var1, String var2);
    //通过type和默认的name获得对象
    <T> T getInstance(Class<T> var1);
    //根据type获取与这个type所对应的容器中的所有注册过的name。
    Set<String> getInstanceNames(Class<?> var1);
    //设置当前线程的作用范围的策略。
    void setScopeStrategy(Strategy var1);
    //删除当前线程的作用范围的策略。
    void removeScopeStrategy();
}

从Container的源代码可以看出,容器的作用有以下三点:

①,获取对象实例。

②,对象的依赖注入。

③,处理对象的作用范围策略。

其中最重要的是第一点和第二点。那么,我们可以通过Container来获取对象的实例,具体来说,哪些实例我们可以获取到呢?

其实我们获取的是xml配置文件中的bean节点的对象和constant节点的参数。

我们来看官方文档对bean节点的解释:

从官方的解释可以看出,bean是被框架的容器创建的,并且被容器注入到框架内部对象中去。

其实从命名就可以看出来,inject就是注入的意思。当我们把某个对象实例作为参数传入到inject方法中时,框架会扫描该对象内部声明有@Inject注解的字段,方法,构造函数或者是方法参数,并将它们注入容器中的管理对象。

因此,所谓struts2的依赖注入其实就是在需要被注入的字段,方法,构造函数或者方法参数上加上@Inject注解就可以了。

对象的注入依赖

具体进入ContainerImpl这个类看看,具体的实现我们就不细说了,看看关于injector和@inject主要的几个方法和字段,弄明白为什么。(这对我来说已经很吃力了。)

package com.opensymphony.xwork2.inject;

class ContainerImpl implements Container {
    //Key存储的是<bean>中对应的type和name,InternalFactory可以理解为工厂
    final Map<Key<?>, InternalFactory<?>> factories;
    //存储tpye-names的映射
    final Map<Class<?>, Set<String>> factoryNamesByType;
    //注入器,可以注意到使用了ReferenceCache作为缓存。具体的create方法之后说明
    final Map<Class<?>, List<ContainerImpl.Injector>> injectors = new ReferenceCache<Class<?>, List<ContainerImpl.Injector>>() {
        protected List<ContainerImpl.Injector> create(Class<?> key) {
            List<ContainerImpl.Injector> injectors = new ArrayList();
            ContainerImpl.this.addInjectors(key, injectors);
            return injectors;
        }
    };
    //构造方法上的注入器
    Map<Class<?>, ContainerImpl.ConstructorInjector> constructors = new ReferenceCache<Class<?>, ContainerImpl.ConstructorInjector>() {
        protected ContainerImpl.ConstructorInjector<?> create(Class<?> implementation) {
            return new ContainerImpl.ConstructorInjector(ContainerImpl.this, implementation);
        }
    };
    //ThreadLocal保证线程安全 一个是object数组、一个是object对象
    ThreadLocal<Object[]> localContext = new ThreadLocal<Object[]>() {
        protected Object[] initialValue() {
            return new Object[1];
        }
    };

    //构造函数,主要工作见注释
    ContainerImpl(Map<Key<?>, InternalFactory<?>> factories) {
        this.factories = factories;
        Map<Class<?>, Set<String>> map = new HashMap();

        Iterator i$;
        Key key;
        Object names;
        //合并相同type不同name的类
        for(i$ = factories.keySet().iterator(); i$.hasNext(); ((Set)names).add(key.getName())) {
            key = (Key)i$.next();
            names = (Set)map.get(key.getType());
            if (names == null) {
                names = new HashSet();
                map.put(key.getType(), names);
            }
        }

        i$ = map.entrySet().iterator();

        while(i$.hasNext()) {
            Entry<Class<?>, Set<String>> entry = (Entry)i$.next();
            //不可更改的集合
            entry.setValue(Collections.unmodifiableSet((Set)entry.getValue()));
        }
        //不可更改的k-v
        this.factoryNamesByType = Collections.unmodifiableMap(map);
    }

    //添加注入器,递归调用,最终要调用到addInjectorsForMembers(..)
    void addInjectors(Class clazz, List<ContainerImpl.Injector> injectors) {
        if (clazz != Object.class) {
            this.addInjectors(clazz.getSuperclass(), injectors);
            //字段的注入器,即@inject注解作用的字段
            this.addInjectorsForFields(clazz.getDeclaredFields(), false, injectors);
            this.addInjectorsForMethods(clazz.getDeclaredMethods(), false, injectors);
        }
    }
 
    //方法上的@inject注入器
    void addInjectorsForMethods(Method[] methods, boolean statics, List<ContainerImpl.Injector> injectors) {
        //最终调用的放法
        this.addInjectorsForMembers(Arrays.asList(methods), statics, injectors, new ContainerImpl.InjectorFactory<Method>() {
            public ContainerImpl.Injector create(ContainerImpl container, Method method, String name) throws ContainerImpl.MissingDependencyException {
                return new ContainerImpl.MethodInjector(container, method, name);
            }
        });
    }
    //字段上的@inject注入器
    void addInjectorsForFields(Field[] fields, boolean statics, List<ContainerImpl.Injector> injectors) {
        this.addInjectorsForMembers(Arrays.asList(fields), statics, injectors, new ContainerImpl.InjectorFactory<Field>() {
            public ContainerImpl.Injector create(ContainerImpl container, Field field, String name) throws ContainerImpl.MissingDependencyException {
                return new ContainerImpl.FieldInjector(container, field, name);
            }
        });
    }
    //添加注入器成员,加入injectors中
    <M extends Member & AnnotatedElement> void addInjectorsForMembers(List<M> members, boolean statics, List<ContainerImpl.Injector> injectors, ContainerImpl.InjectorFactory<M> injectorFactory) {
        Iterator i$ = members.iterator();

        while(true) {
            Member member;
            Inject inject;
            do {
                do {
                    if (!i$.hasNext()) {
                        return;
                    }

                    member = (Member)i$.next();
                } while(this.isStatic(member) != statics);

                inject = (Inject)((AnnotatedElement)member).getAnnotation(Inject.class);
            } while(inject == null);

            try {
                injectors.add(injectorFactory.create(this, member, inject.value()));
            } catch (ContainerImpl.MissingDependencyException var9) {
                if (inject.required()) {
                    throw new DependencyException(var9);
                }
            }
        }
    }

    //获得方法参数的注入器
    <M extends AccessibleObject & Member> ContainerImpl.ParameterInjector<?>[] getParametersInjectors(M member, Annotation[][] annotations, Class[] parameterTypes, String defaultName) throws ContainerImpl.MissingDependencyException {
        
    }
    //生成方法参数的注入器
    <T> ContainerImpl.ParameterInjector<T> createParameterInjector(Key<T> key, Member member) throws ContainerImpl.MissingDependencyException {
        
    }

    //获得被注入对象的实例,依次调用了ParameterInjector类的inject方法,注意到它并没实现Injector接口
    private static Object[] getParameters(Member member, InternalContext context, ContainerImpl.ParameterInjector[] parameterInjectors) {
        if (parameterInjectors == null) {
            return null;
        } else {
            Object[] parameters = new Object[parameterInjectors.length];

            for(int i = 0; i < parameters.length; ++i) {
                //需要注入的方法参数的值
                parameters[i] = parameterInjectors[i].inject(member, context);
            }

            return parameters;
        }

    }
    //完成对象o的依赖注入操作的对外接口
    public void inject(final Object o) {
        this.callInContext(new ContainerImpl.ContextualCallable<Void>() {
            public Void call(InternalContext context) {
                //内部实现的具体方法
                ContainerImpl.this.inject(o, context);
                return null;
            }
        });
    }
    //内部实现的具体方法
    void inject(Object o, InternalContext context) {
        //获得注入对象o相同class的注入器
        List<ContainerImpl.Injector> injectors = (List)this.injectors.get(o.getClass());
        Iterator i$ = injectors.iterator();
        //将该对象o通过注入器注入
        while(i$.hasNext()) {
            ContainerImpl.Injector injector = (ContainerImpl.Injector)i$.next();
            //这里我们可以看看具体的injector注入器类的inject方法
            injector.inject(context, o);
        }

    }
    //创建一个类的实例并进行对象的依赖注入操作,这里就和构造函数有关了
    public <T> T inject(final Class<T> implementation) {
        return this.callInContext(new ContainerImpl.ContextualCallable<T>() {
            public T call(InternalContext context) {
                return ContainerImpl.this.inject(implementation, context);
            }
        });
    }
    //内部实现
    <T> T inject(Class<T> implementation, InternalContext context) {
        try {
            //获得该class的构造器
            ContainerImpl.ConstructorInjector<T> constructor = this.getConstructor(implementation);
            return implementation.cast(constructor.construct(context, implementation));
        } catch (Exception var4) {
            throw new RuntimeException(var4);
        }
    }
    //这个类我还不太清楚什么作用,请求的上下文?
    <T> T callInContext(ContainerImpl.ContextualCallable<T> callable) {
        Object[] reference = (Object[])this.localContext.get();
        if (reference[0] == null) {
            reference[0] = new InternalContext(this);

            Object var3;
            try {
                //一般会执行这一句
                var3 = callable.call((InternalContext)reference[0]);
            } finally {
                reference[0] = null;
                this.localContext.remove();
            }

            return var3;
        } else {
            return callable.call((InternalContext)reference[0]);
        }
    }
    //注入器统一的接口
    interface Injector extends Serializable {
        void inject(InternalContext var1, Object var2);
    }

    interface ContextualCallable<T> {
        T call(InternalContext var1);
    }
    //字段注入器
    static class FieldInjector implements ContainerImpl.Injector {}

    //方法注入器
    static class MethodInjector implements ContainerImpl.Injector {}

    //参数注入器
    static class ParameterInjector<T> {}

    //构造方法注入器
    static class ConstructorInjector<T> {}
    
    interface InjectorFactory<M extends Member & AnnotatedElement> {
        ContainerImpl.Injector create(ContainerImpl var1, M var2, String var3) throws ContainerImpl.MissingDependencyException;
    }
}

 以上的代码虽然做了注解,但是我在关于构造方法上的注入器的具体实现还是不太明白,特别是construct(...)方法,暂时放放,总结一下大概是如何实现的:

字段注入器:关键的类就是:ContainerImpl.FieldInjector,一个FieldInjector保存的就是一个需要注入(被@inject注解)的字段信息,这里就是反射应用的最好体现了,一切操作都是在程序运行过程完成的。inject()方法完成了对了字段的注入操作。

//字段注入器
    static class FieldInjector implements ContainerImpl.Injector {
        //保存了该字段
        final Field field;
        //字段工厂
        final InternalFactory<?> factory;
        final ExternalContext<?> externalContext;

        public FieldInjector(ContainerImpl container, Field field, String name) throws ContainerImpl.MissingDependencyException {
            this.field = field;
            //修改可见性
            if (!field.isAccessible()) {
                SecurityManager sm = System.getSecurityManager();

                try {
                    if (sm != null) {
                        sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
                    }

                    field.setAccessible(true);
                } catch (AccessControlException var6) {
                    throw new DependencyException("Security manager in use, could not access field: " + field.getDeclaringClass().getName() + "(" + field.getName() + ")", var6);
                }
            }
            //保存信息
            Key<?> key = Key.newInstance(field.getType(), name);
            this.factory = container.getFactory(key);
            if (this.factory == null) {
                throw new ContainerImpl.MissingDependencyException("No mapping found for dependency " + key + " in " + field + ".");
            } else {
                this.externalContext = ExternalContext.newInstance(field, key, container);
            }
        }
        //字段注入可能比较好理解
        public void inject(InternalContext context, Object o) {
            ExternalContext<?> previous = context.getExternalContext();
            context.setExternalContext(this.externalContext);
            //将对象注入给field的
            try {
                this.field.set(o, this.factory.create(context));
            } catch (IllegalAccessException var8) {
                throw new AssertionError(var8);
            } finally {
                context.setExternalContext(previous);
            }

        }
    }

方法注入器,关注到的ContainerImpl.MethodInjector,一个MethodInjector保存一个方法以及方法上需要注入的参数(参数注入器)。主要的inject()方法调用对象o的method,并将参数注入,其中getParameters()是获得需要注入的参数的值

    //方法注入器
    static class MethodInjector implements ContainerImpl.Injector {
        //保存了该方法
        final Method method;
        //方法的参数,主要是要注入参数
        final ContainerImpl.ParameterInjector<?>[] parameterInjectors;

        public MethodInjector(ContainerImpl container, Method method, String name) throws ContainerImpl.MissingDependencyException {
            this.method = method;
            if (!method.isAccessible()) {
                SecurityManager sm = System.getSecurityManager();

                try {
                    if (sm != null) {
                        sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
                    }

                    method.setAccessible(true);
                } catch (AccessControlException var6) {
                    throw new DependencyException("Security manager in use, could not access method: " + name + "(" + method.getName() + ")", var6);
                }
            }
            //获得方法参数
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 0) {
                throw new DependencyException(method + " has no parameters to inject.");
            } else {
                //获得方法参数的注入器
                this.parameterInjectors = container.getParametersInjectors(method, method.getParameterAnnotations(), parameterTypes, name);
            }
        }

        public void inject(InternalContext context, Object o) {
            try {
                //调用对象o的method,并将参数注入,所以getParameters获得需要注入的参数的实例
                //相当于o.method(ContainerImpl.getParameters(this.method, context, this.parameterInjectors))
                this.method.invoke(o, ContainerImpl.getParameters(this.method, context, this.parameterInjectors));
            } catch (Exception var4) {
                throw new RuntimeException(var4);
            }
        }
    }

 参数注入器:保存的参数的信息。注意到的是这个ParameterInjector并没有实现Injector接口,它的inject()方法发生在:

    private static Object[] getParameters(Member member, InternalContext context, ContainerImpl.ParameterInjector[] parameterInjectors) {
        if (parameterInjectors == null) {
            return null;
        } else {
            Object[] parameters = new Object[parameterInjectors.length];
            //获得需要注入的参数的实例,依次调用了ParameterInjector类的inject方法,注意到它并没实现Injector接口
            for(int i = 0; i < parameters.length; ++i) {
                parameters[i] = parameterInjectors[i].inject(member, context);
            }

            return parameters;
        }
    }

而getParameters()方法发生在方法注入器的inject()和构造器注入器的construct()中,传入的member分别是method(Method)和construct(Construct)。所以总结下来inject()返回了注入参数的实例

    //参数注入器
    static class ParameterInjector<T> {
        final ExternalContext<T> externalContext;
        //保存了参数的信息
        final InternalFactory<? extends T> factory;

        public ParameterInjector(ExternalContext<T> externalContext, InternalFactory<? extends T> factory) {
            this.externalContext = externalContext;
            this.factory = factory;
        }
        //方法参数的注入,实际上是获得需要注入的参数的实例
        T inject(Member member, InternalContext context) {
            //获得外部上下文的操作
            ExternalContext<?> previous = context.getExternalContext();
            context.setExternalContext(this.externalContext);

            Object var4;
            try {
                //生成注入参数的实例
                var4 = this.factory.create(context);
            } finally {
                context.setExternalContext(previous);
            }

            return var4;
        }
    }

 构造器注入器:这个ConstructorInjector也没有实现Injector接口。主要的方法就是 findConstructorIn(...)找到带@inject注解的构造器,constructorParameterInjector(...)返回需要注入参数的参数注入器。关于construct(...)我们需要从它的作用地方推测一下:

    <T> T inject(Class<T> implementation, InternalContext context) {
        try {
            ContainerImpl.ConstructorInjector<T> constructor = this.getConstructor(implementation);
            return implementation.cast(constructor.construct(context, implementation));
        } catch (Exception var4) {
            throw new RuntimeException(var4);
        }
    }

前面代码我们提到的这个方法的作用(见注释),我们先看一下第一句:getConstruct(implementation)

    <T> ContainerImpl.ConstructorInjector<T> getConstructor(Class<T> implementation) {
        return (ContainerImpl.ConstructorInjector)this.constructors.get(implementation);
    }

    Map<Class<?>, ContainerImpl.ConstructorInjector> constructors = new ReferenceCache<Class<?>, ContainerImpl.ConstructorInjector>() {
        protected ContainerImpl.ConstructorInjector<?> create(Class<?> implementation) {
            return new ContainerImpl.ConstructorInjector(ContainerImpl.this, implementation);
        }
    };

这里会涉及到关于ReferenceCache和它的父类ReferenceMap的相关知识,我们在只说明一下get操作的结果:当获取不到相应的注入器时,就会带到了create()方法,于是调用到了ConstructorInjector的构造器。那么类似于方法构造器,这里就会生成完整的一个构造注入器。


注意:下面语句也是同样的道理。

    //内部实现的具体方法
    void inject(Object o, InternalContext context) {
...
        List<ContainerImpl.Injector> injectors = (List)this.injectors.get(o.getClass());
...
    }

return implementation.cast(constructor.construct(context, implementation));

 这一句应该就是完成对象的创建和依赖部分的注入了。 

 
    //构造方法注入器
    static class ConstructorInjector<T> {
        //class
        final Class<T> implementation;
        final List<ContainerImpl.Injector> injectors;
        //构造方法
        final Constructor<T> constructor;
        //参数注入器
        final ContainerImpl.ParameterInjector<?>[] parameterInjectors;
        //
        ConstructorInjector(ContainerImpl container, Class<T> implementation) {
            this.implementation = implementation;
            //找到带@inject注解的构造器
            this.constructor = this.findConstructorIn(implementation);
            //修改可达性
            if (!this.constructor.isAccessible()) {
                SecurityManager sm = System.getSecurityManager();

                try {
                    if (sm != null) {
                        sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
                    }

                    this.constructor.setAccessible(true);
                } catch (AccessControlException var8) {
                    throw new DependencyException("Security manager in use, could not access constructor: " + implementation.getName() + "(" + this.constructor.getName() + ")", var8);
                }
            }

            ContainerImpl.MissingDependencyException exception = null;
            Inject inject = null;
            ContainerImpl.ParameterInjector[] parameters = null;

            try {
                //获取需要注入的参数
                inject = (Inject)this.constructor.getAnnotation(Inject.class);
                parameters = this.constructParameterInjector(inject, container, this.constructor);
            } catch (ContainerImpl.MissingDependencyException var7) {
                exception = var7;
            }

            this.parameterInjectors = parameters;
            if (exception != null && inject != null && inject.required()) {
                throw new DependencyException(exception);
            } else {
                this.injectors = (List)container.injectors.get(implementation);
            }
        }
        //找到@inject的参数
        ContainerImpl.ParameterInjector<?>[] constructParameterInjector(Inject inject, ContainerImpl container, Constructor<T> constructor) throws ContainerImpl.MissingDependencyException {
            return constructor.getParameterTypes().length == 0 ? null : container.getParametersInjectors(constructor, constructor.getParameterAnnotations(), constructor.getParameterTypes(), inject.value());
        }
        //找到带注解@inject的构造器
        private Constructor<T> findConstructorIn(Class<T> implementation) {
            Constructor<T> found = null;
            Constructor<T>[] declaredConstructors = (Constructor[])implementation.getDeclaredConstructors();
            Constructor[] arr$ = declaredConstructors;
            int len$ = declaredConstructors.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                Constructor<T> constructor = arr$[i$];
                if (constructor.getAnnotation(Inject.class) != null) {
                    if (found != null) {
                        throw new DependencyException("More than one constructor annotated with @Inject found in " + implementation + ".");
                    }

                    found = constructor;
                }
            }

            if (found != null) {
                return found;
            } else {
                try {
                    return implementation.getDeclaredConstructor();
                } catch (NoSuchMethodException var8) {
                    throw new DependencyException("Could not find a suitable constructor in " + implementation.getName() + ".");
                }
            }
        }

    Object construct(InternalContext context, Class<? super T> expectedType) {
            ConstructionContext<T> constructionContext =         context.getConstructionContext(this);
            if (constructionContext.isConstructing()) {
                return constructionContext.createProxy(expectedType);
            } else {
                T t = constructionContext.getCurrentReference();
                if (t != null) {
                    return t;
                } else {
                    try {
                        constructionContext.startConstruction();

                        try {
                            Object[] parameters = ContainerImpl.getParameters(this.constructor, context, this.parameterInjectors);
                            //构造对象
                            t = this.constructor.newInstance(parameters);
                            constructionContext.setProxyDelegates(t);
                        } finally {
                            constructionContext.finishConstruction();
                        }

                        constructionContext.setCurrentReference(t);
                        Iterator i$ = this.injectors.iterator();
                        //完成依赖部分的注入
                        while(i$.hasNext()) {
                            ContainerImpl.Injector injector = (ContainerImpl.Injector)i$.next();
                            injector.inject(context, t);
                        }

                        Object var18 = t;
                        return var18;
                    } catch (IllegalAccessException | InvocationTargetException | InstantiationException var15) {
                        throw new RuntimeException(var15);
                    } finally {
                        constructionContext.removeCurrentReference();
                    }
                }
            }
        }
    }

对象注入的实例

//发生在DefaultConfiguration.reloadContainer()
//假设注入的对象是StrutsXmlConfigurationProvider

this.container.inject(containerProvider);

我们直接跳到起作用的方法中:

//其中o就是StrutsXmlConfigurationProvider
//暂时忽略context

    void inject(Object o, InternalContext context) {
        //这里会获得StrutsXmlConfigurationProvider中的注入器,也就是需要注入的地方,查看父类我们会发现两个方法如下
        List<ContainerImpl.Injector> injectors = (List)this.injectors.get(o.getClass());
        Iterator i$ = injectors.iterator();

        while(i$.hasNext()) {
            //依次注入,这两个是方法上的注入器
            ContainerImpl.Injector injector = (ContainerImpl.Injector)i$.next();
            injector.inject(context, o);
        }

    }

XmlConfigurationProvider

    @Inject
    public void setObjectFactory(ObjectFactory objectFactory) {
        this.objectFactory = objectFactory;
    }

    @Inject
    public void setFileManagerFactory(FileManagerFactory fileManagerFactory) {
        this.fileManager = fileManagerFactory.getFileManager();
    }

 那么接下来应该会依次调用两个方法的注入器:injector.inject(context,o)

MethodInjector.inject
        
        public void inject(InternalContext context, Object o) {
            try {
                //调用两个方法
                this.method.invoke(o, ContainerImpl.getParameters(this.method, context, this.parameterInjectors));
            } catch (Exception var4) {
                throw new RuntimeException(var4);
            }
        }

 这里就相当于,getParameters()就是获得实例对象

o.setObjectFactory(ContainerImpl.getParameters(this.method, context, this.parameterInjectors))

那么接下来的就不多赘述了,我们可以直接看ParamtersInjector.inject(),它会去create一个实例以供注入。

        T inject(Member member, InternalContext context) {
            ExternalContext<?> previous = context.getExternalContext();
            context.setExternalContext(this.externalContext);

            Object var4;
            try {
                //生成实例
                var4 = this.factory.create(context);
            } finally {
                context.setExternalContext(previous);
            }

            return var4;
        }

 

获取对象实例 

这个似乎没有什么需要细说的地方,主要步骤就是通过type和name获取内部工厂,然后生成对象。涉及到factories可以参考factories

    <T> InternalFactory<? extends T> getFactory(Key<T> key) {
        return (InternalFactory)this.factories.get(key);
    }

    <T> T getInstance(Class<T> type, String name, InternalContext context) {
        ExternalContext<?> previous = context.getExternalContext();
        Key<T> key = Key.newInstance(type, name);
        context.setExternalContext(ExternalContext.newInstance((Member)null, key, this));

        Object var7;
        try {
            InternalFactory o = this.getFactory(key);
            if (o != null) {
                var7 = this.getFactory(key).create(context);
                return var7;
            }

            var7 = null;
        } finally {
            context.setExternalContext(previous);
        }

        return var7;
    }

    <T> T getInstance(Class<T> type, InternalContext context) {
        return this.getInstance(type, "default", context);
    }

关于Container的内容就暂时到这吧。还有存在很多不足的地方,希望慢慢也能快点理解改正。

下一篇:Dispatcher(2)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章