Struts2作为一个Web MVC框架,自身提供了一个IoC容器,实现对对象的生命周期管理,核心功能就是将对象注入到容器以及从容器中获取对象。通过对struts2容器的分析,学习和探讨一下IoC的思想。
<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从容器中获取对象。
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>>() { @Override protected 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); } } } } } }
reloadContainer方法中构建了两个Container,一个是bootstrap,主要完成对containerProvider的完整初始化,另外一个是全局的Container--container,即struts主要完成IoC的构件,它们的构建方法都一样,使用了构建模式,下面以container为例来分析。
ContainerBuilder builder = new ContainerBuilder();#创建ContainerBuiler Container 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); ......
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); ...... } }
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中
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
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的创建。
在DefaultConfiguration.reloadContainer中
objectFactory = container.getInstance(ObjectFactory.class)
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,再调用scopeFactory的create去获取实例,如果实例不存在,再去调用scopeFactory包装的factory.create,即context.getContainerImpl().getConstructor(implementation);return (T) constructor.construct(context, type);
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> <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"/>
在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时,将bean的factory保存在ContainerImp中,将bean交给容器管理
在struts2对url进行处理时,解析完url,分析完namespace, action, method后,创建完ActionProxyFactory,由ActionProxyFactory创建ActionInvocation,ActionProxy后,由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 ......
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; }
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); } } }