您的位置:首页 > 编程语言 > Java开发

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

2015-05-07 20:53 441 查看

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>>() {
@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);
}
}
}
}
}
}

Container构建

DefaultConfiguration

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


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,再调用scopeFactory的create去获取实例,如果实例不存在,再去调用scopeFactory包装的factory.create,即context.getContainerImpl().getConstructor(implementation);return (T) constructor.construct(context, type);

Struts2应用中Container的应用

Action中Inject业务逻辑类

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时,将bean的factory保存在ContainerImp中,将bean交给容器管理

DefaultActionInvocation

在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
......


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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: