Struts2容器详解---IoC源码分析

来源:互联网 发布:网络用语开车什么意思 编辑:程序博客网 时间:2024/06/17 00:00


Struts2作为一个Web MVC框架,自身提供了一个IoC容器,实现对对象的生命周期管理,核心功能就是将对象注入到容器以及从容器中获取对象。通过对struts2容器的分析,学习和探讨一下IoC的思想。

Container接口定义

<span style="color:#000000;">package com.opensymphony.xwork2.inject;</span><span style="color:#000000;">public interface Container extends Serializable {  ......  /* Injects dependencies into the fields and methods of an existing object.  void inject(Object o);  /* Creates and injects a new instance of type.  <T> T inject(Class<T> implementation);  /* Gets an instance of the given dependency which was declared in  <T> T getInstance(Class<T> type, String name);  /* Convenience method.  <T> T getInstance(Class<T> type);    ......}</span>

接口的定义很明确, Container是通过重载的inject方法实现对象的注入, 通过getInstance从容器中获取对象。

 

Container实现ContainerImpl

package com.opensymphony.xwork2.inject;class ContainerImpl implements Container {    //key是对Class<T> 和Name的封装, factories维护着Key和Class类型的工厂    final Map<Key<?>, InternalFactory<?>> factories;    //factoryNamesByType维护着Class和Class类型实例名的映射    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);    }    <T> InternalFactory<? extends T> getFactory( Key<T> key ) { return (InternalFactory<T>) factories.get(key);    }    /*Field and method injectors.    final Map<Class<?>, List<Injector>> injectors =new ReferenceCache<Class<?>, List<Injector>>() {@Overrideprotected List<Injector> create( Class<?> key ) {            List<Injector> injectors = new ArrayList<Injector>();    addInjectors(key, injectors);    return injectors;}    };    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 addInjectorsForMethods( Method[] methods, boolean statics, List<Injector> injectors ) {        addInjectorsForMembers(Arrays.asList(methods), statics, injectors,    new InjectorFactory<Method>() {    public Injector create( ContainerImpl container, Method method,String name ) throws MissingDependencyException {return new MethodInjector(container, method, name);    }        });    }    void addInjectorsForFields( Field[] fields, boolean statics,List<Injector> injectors ) {addInjectorsForMembers(Arrays.asList(fields), statics, injectors,new InjectorFactory<Field>() {            public Injector create( ContainerImpl container, Field field,String name ) throws MissingDependencyException {return new FieldInjector(container, field, name);    }});    }    <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) {Inject inject = member.getAnnotation(Inject.class);if (inject != null) {    try {injectors.add(injectorFactory.create(this, member, inject.value()));    } catch ( MissingDependencyException e ) {if (inject.required()) {    throw new DependencyException(e);}    }}    }}    }

Container构建

DefaultConfiguration

reloadContainer方法中构建了两个Container,一个是bootstrap,主要完成对containerProvider的完整初始化,另外一个是全局的Container--container,即struts主要完成IoC的构件,它们的构建方法都一样,使用了构建模式,下面以container为例来分析。

ContainerBuilder builder = new ContainerBuilder();#创建ContainerBuilerContainer bootstrap = createBootstrapContainer(providers);for (final ContainerProvider containerProvider : providers){    bootstrap.inject(containerProvider);    containerProvider.init(this);    containerProvider.register(builder, props);
    #其中有BeanSelectionProvider,在dispatcher的init方法中调用init_AliasStandardObjects中加入providers中}props.setConstants(builder);builder.factory(Configuration.class, new Factory<Configuration>() {    public Configuration create(Context context) throws Exception {return DefaultConfiguration.this;    }});ActionContext oldContext = ActionContext.getContext();try {    ......    container = builder.create(false);#ContainerBuilder构建Container    setContext(container);    objectFactory = container.getInstance(ObjectFactory.class);    ......

BeanSelectionProvider

register方法

public void register(ContainerBuilder builder, LocatableProperties props) {    alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props);    alias(FileManagerFactory.class, StrutsConstants.STRUTS_FILE_MANAGER_FACTORY, builder, props, Scope.SINGLETON);......}void alias(Class type, String key, ContainerBuilder builder, Properties props) {    alias(type, key, builder, props, Scope.SINGLETON);}

alias方法

void alias(Class type, String key, ContainerBuilder builder, Properties props, Scope scope) {    if (!builder.contains(type)) {        ......        builder.factory(type, cls, scope);        ......    }}

ContainerBuilder

public <T> ContainerBuilder factory(Class<T> type,      Class<? extends T> implementation, Scope scope) {    return factory(type, Container.DEFAULT_NAME, implementation, scope);}public <T> ContainerBuilder factory(final Class<T> type, final String name,    final Class<? extends T> implementation, final Scope scope) {        InternalFactory<? extends T> factory = new InternalFactory<T>() {    volatile ContainerImpl.ConstructorInjector<? extends T> constructor;    @SuppressWarnings("unchecked")    public T create(InternalContext context) {        if (constructor == null) {    this.constructor = context.getContainerImpl().getConstructor(implementation);}return (T) constructor.construct(context, type);//先得到类的构造器,再用构造器构造一个类的实例    }    ......    };    return factory(Key.newInstance(type, name), factory, scope);}private <T> ContainerBuilder factory(final Key<T> key,    InternalFactory<? extends T> factory, Scope scope) {    ensureNotCreated();    checkKey(key);    final InternalFactory<? extends T> scopedFactory =        scope.scopeFactory(key.getType(), key.getName(), factory);    factories.put(key, scopedFactory);    if (scope == Scope.SINGLETON) {        singletonFactories.add(new InternalFactory<T>() {        public T create(InternalContext context) {            try {               context.setExternalContext(ExternalContext.newInstance(null, key, context.getContainerImpl()));               return scopedFactory.create(context);            } finally {               context.setExternalContext(null);            }        }      });    }    return this;}

//scopedFactory包装了一个factory,将对象工厂scopedFactory存放在factories

Scope

SINGLETON {    @Override    <T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name,        final InternalFactory<? extends T> factory) {        return new InternalFactory<T>() {        T instance;        public T create(InternalContext context) {          synchronized (context.getContainer()) {            if (instance == null) {              instance = factory.create(context);            }            return instance;          }        }        @Override        public String toString() {          return factory.toString();        }      };    }  },

Singleton类型的scopeFactory内部保存一个T类型的实例,而create方法保证每次都返回同一个T实例,即单例T

THREAD {    @Override    <T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name,        final InternalFactory<? extends T> factory) {        return new InternalFactory<T>() {        final ThreadLocal<T> threadLocal = new ThreadLocal<T>();        public T create(final InternalContext context) {          T t = threadLocal.get();          if (t == null) {            t = factory.create(context);            threadLocal.set(t);          }          return t;        }        @Override        public String toString() {          return factory.toString();        }      };    }  },

Thread类型的scopeFactory内部保存一个ThreadLocal<T>类型的实例,而create方法保证同一个线程每次都返回同一个T实例,即线程单例T

Container 构建--构建者模式

package com.opensymphony.xwork2.inject;public final class ContainerBuilder {    final Map<Key<?>, InternalFactory<?>> factories =      new HashMap<Key<?>, InternalFactory<?>>();    final List<InternalFactory<?>> singletonFactories =      new ArrayList<InternalFactory<?>>();    ......    public <T> ContainerBuilder factory(......    .....    public Container create(boolean loadSingletons) {        ensureNotCreated();        created = true;        final ContainerImpl container = new ContainerImpl(            new HashMap<Key<?>, InternalFactory<?>>(factories));        if (loadSingletons) {           container.callInContext(new ContainerImpl.ContextualCallable<Void>() {               public Void call(InternalContext context) {                  for (InternalFactory<?> factory : singletonFactories) {                      factory.create(context);                  }                  return null;                }             });        }        container.injectStatics(staticInjections);        return container;      }}

一组重载的factory完成对factories的构建,create方法利用构建好的factories完成Container的创建。

Struts2框架内应用例子--ObjectFactory

DefaultConfiguration.reloadContainer

objectFactory = container.getInstance(ObjectFactory.class)

ContainerImpl

public <T> T getInstance( final Class<T> type ) {    return callInContext(new ContextualCallable<T>() {        public T call( InternalContext context ) {    return getInstance(type, context);}    });}<T> T callInContext( ContextualCallable<T> callable ) {    Object[] reference = localContext.get();    if (reference[0] == null) {        reference[0] = new InternalContext(this);try {    return callable.call((InternalContext) reference[0]);} finally {    reference[0] = null;    localContext.remove();}    } else {return callable.call((InternalContext) reference[0]);    }}<T> T getInstance( Class<T> type, InternalContext context ) {    return getInstance(type, DEFAULT_NAME, context);}<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(null, key, this));    try {InternalFactory o = getFactory(key);if (o != null) {            return getFactory(key).create(context);} else {    return null;}    } finally {context.setExternalContext(previous);    }}

//首先通过getFactory(key)得到单例的scopeFactory,再调用scopeFactorycreate去获取实例,如果实例不存在,再去调用scopeFactory包装的factory.create,即context.getContainerImpl().getConstructor(implementation);return (T) constructor.construct(context, type);

Struts2应用中Container的应用

ActionInject业务逻辑类

public class LoginAction extends ActionSupport {    @Inject( "userService")    private UserService usersrv;    private String username;    private String password;    //省略get/set    public String login() {UserInfo user = usersrv.getUser(username, password);if (user != null) {            return SUCCESS;}return INPUT;    }    ......}

struts.xml

<struts><bean name="userService" type="com.struts.service.UserService" class="com.struts.service.UserService" />    <constant name="struts.enable.DynamicMethodInvocation" value="true" />    <constant name="struts.devMode" value="true" />     <package name="default" extends="struts-default"><default-action-ref name="index"/>

XmlConfigurationProvider

struts初始化时,在DefaultConfiguration.reloadContainer中调用containerProvider.register(builder, props);

public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {    ......    for (Document doc : documents) {        ......if ("bean".equals(nodeName)) {    String type = child.getAttribute("type");    String name = child.getAttribute("name");    String impl = child.getAttribute("class");    ......    try {Class cimpl = ClassLoaderUtil.loadClass(impl, getClass());Class ctype = cimpl;......cimpl.getDeclaredConstructors();containerBuilder.factory(ctype, name, new LocatableFactory(name, ctype, cimpl, scope, childNode), scope);    }

//在解析struts.xml时,将beanfactory保存在ContainerImp中,将bean交给容器管理

DefaultActionInvocation

struts2url进行处理时,解析完url,分析完namespace, action, method后,创建完ActionProxyFactory,ActionProxyFactory创建ActionInvocationActionProxy后,由DefaultActionInvocation创建Action

protected void createAction(Map<String, Object> contextMap) {    String timerKey = "actionCreate: " + proxy.getActionName();    try {UtilTimerStack.push(timerKey);action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);    } catch     ......

ObjectFactory

public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception {    return buildBean(config.getClassName(), extraContext);}public Object buildBean(String className, Map<String, Object> extraContext) throws Exception {    return buildBean(className, extraContext, true);}public Object buildBean(String className, Map<String, Object> extraContext, boolean injectInternal) throws Exception {    Class clazz = getClassInstance(className);    Object obj = buildBean(clazz, extraContext);    //利用反射构建Action类实例    if (injectInternal) { injectInternalBeans(obj);//IoC,注入依赖的Bean    }    return obj;}protected Object injectInternalBeans(Object obj) {    if (obj != null && container != null) {container.inject(obj);    }    return obj;}

ContainerImpl.inject

public void inject( final Object o ) {    callInContext(new ContextualCallable<Void>() {        public Void call( InternalContext context ) {    inject(o, context);    return null;}    });}<T> T callInContext( ContextualCallable<T> callable ) {    Object[] reference = localContext.get();    if (reference[0] == null) {reference[0] = new InternalContext(this);try {            return callable.call((InternalContext) reference[0]);} finally {    // Only remove the context if this call created it.    reference[0] = null;    // WW-3768: ThreadLocal was not removed    localContext.remove();}    } else {// Someone else will clean up this context.return callable.call((InternalContext) reference[0]);    }}实际上会调用inject(object,InternalContext)void inject( Object o, InternalContext context ) {    List<Injector> injectors = this.injectors.get(o.getClass());    for ( Injector injector : injectors ) {injector.inject(context, o);    }}在injectors中找到Action类里面被@inject注释的field/method,然后执行field/mehtold的inject,在本例中是field被注解了static class FieldInjector implements Injector {    ......    public void inject( InternalContext context, Object o ) {        ExternalContext<?> previous = context.getExternalContext();context.setExternalContext(externalContext);try {    field.set(o, factory.create(context));//利用反射将对象的注解field设置成容器中管理对实例} catch ( IllegalAccessException e ) {    throw new AssertionError(e);} finally {    context.setExternalContext(previous);}    }} 




0 0
原创粉丝点击