在Struts2中,InternalFactory用于创建将被注入容器的对象
以struts配置中默认的bean为例:
a.向容器中注入bean对象
containerBuilder.factory(ctype, name, new LocatableFactory(name, ctype, cimpl, scope, childNode), scope);
b.从InternalContext中获取Context
public <T> ContainerBuilder factory(final Class<T> type, final String name,
final Factory<? extends T> factory, Scope scope) {
InternalFactory<T> internalFactory =
new InternalFactory<T>() {
public T create(InternalContext context) {
try {
Context externalContext = context.getExternalContext();
return factory.create(externalContext);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String toString() {
return new LinkedHashMap<String, Object>() {{
put("type", type);
put("name", name);
put("factory", factory);
}}.toString();
}
};
return factory(Key.newInstance(type, name), internalFactory, scope);
}
3.向factories中注册InternalFactory
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;
}
4.单列模式
Scope.SINGLETON {
<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;
}
}
public String toString() {
return factory.toString();
}
};
}
}
当要从容器中获取对象时,只需要给出类名即可
dispatcher.getContainer().getInstance(ValueStackFactory.class)
这样它会首先去调用SINGLETON的create方法,再调用3的InterFactory,最后调用我们最初传进来的Factory;这样做的好处在于它可以进行单例判断,增加内部上下文,把InternalFactory注册到Container等;
在getInstance的过程中,它同样使用了一些内部类ContextualCallable,因在ContainerImpl的很多方法都涉及到InternalContext参数赋值,所以它在callInContext中做了统一处理,而把变化的调用留给ContextualCallable接口去处理
以struts配置中默认的bean为例:
a.向容器中注入bean对象
containerBuilder.factory(ctype, name, new LocatableFactory(name, ctype, cimpl, scope, childNode), scope);
b.从InternalContext中获取Context
public <T> ContainerBuilder factory(final Class<T> type, final String name,
final Factory<? extends T> factory, Scope scope) {
InternalFactory<T> internalFactory =
new InternalFactory<T>() {
public T create(InternalContext context) {
try {
Context externalContext = context.getExternalContext();
return factory.create(externalContext);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String toString() {
return new LinkedHashMap<String, Object>() {{
put("type", type);
put("name", name);
put("factory", factory);
}}.toString();
}
};
return factory(Key.newInstance(type, name), internalFactory, scope);
}
3.向factories中注册InternalFactory
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;
}
4.单列模式
Scope.SINGLETON {
<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;
}
}
public String toString() {
return factory.toString();
}
};
}
}
当要从容器中获取对象时,只需要给出类名即可
dispatcher.getContainer().getInstance(ValueStackFactory.class)
这样它会首先去调用SINGLETON的create方法,再调用3的InterFactory,最后调用我们最初传进来的Factory;这样做的好处在于它可以进行单例判断,增加内部上下文,把InternalFactory注册到Container等;
在getInstance的过程中,它同样使用了一些内部类ContextualCallable,因在ContainerImpl的很多方法都涉及到InternalContext参数赋值,所以它在callInContext中做了统一处理,而把变化的调用留给ContextualCallable接口去处理