struts2_源码学习_factories
程序员文章站
2022-06-15 14:17:12
...
在ContainerBuilder和Container中最重要的一个字段就是:
final Map<Key<?>, InternalFactory<?>> factories;
从字面上我们可以看出这应该是对应的工厂键值对映射,那么key和value分别存储的是什么呢?
package com.opensymphony.xwork2.inject;
class Key<T> {
final Class<T> type;
final String name;
final int hashCode;
private Key(Class<T> type, String name) {
if (type == null) {
throw new NullPointerException("Type is null.");
} else if (name == null) {
throw new NullPointerException("Name is null.");
} else {
this.type = type;
this.name = name;
this.hashCode = type.hashCode() * 31 + name.hashCode();
}
}
Class<T> getType() {
return this.type;
}
String getName() {
return this.name;
}
public int hashCode() {
return this.hashCode;
}
public boolean equals(Object o) {
if (!(o instanceof Key)) {
return false;
} else if (o == this) {
return true;
} else {
Key other = (Key)o;
return this.name.equals(other.name) && this.type.equals(other.type);
}
}
public String toString() {
return "[type=" + this.type.getName() + ", name='" + this.name + "']";
}
static <T> Key<T> newInstance(Class<T> type, String name) {
return new Key(type, name);
}
}
可以看出Key存储的应该就是<bean>结点中对应的type和name属性。
package com.opensymphony.xwork2.inject;
import java.io.Serializable;
interface InternalFactory<T> extends Serializable {
T create(InternalContext var1);
Class<? extends T> type();
}
而InternalFactory则是一个接口,create()方法应该就是创建一个新的实例,我们需要去看它具体应用的地方。<bean>信息的传递过程应该是从 providers(register) -> builder(create) -> container(new ContainerBuilder)
以StrutsXmlConfigurationProvider为例,它的register方法在父类XmlConfigurationProvider中:
XmlConfigurationProvider.register()
public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
LOG.trace("Parsing configuration file [{}]", this.configFileName);
Map<String, Node> loadedBeans = new HashMap();
Iterator i$ = this.documents.iterator();
while(i$.hasNext()) {
Document doc = (Document)i$.next();
Element rootElement = doc.getDocumentElement();
NodeList children = rootElement.getChildNodes();
int childSize = children.getLength();
for(int i = 0; i < childSize; ++i) {
Node childNode = children.item(i);
if (childNode instanceof Element) {
Element child = (Element)childNode;
String nodeName = child.getNodeName();
String type;
String name;
if ("bean".equals(nodeName)) {
type = child.getAttribute("type");
name = child.getAttribute("name");
String impl = child.getAttribute("class");
String onlyStatic = child.getAttribute("static");
String scopeStr = child.getAttribute("scope");
boolean optional = "true".equals(child.getAttribute("optional"));
Scope scope = Scope.SINGLETON;
if ("prototype".equals(scopeStr)) {
scope = Scope.PROTOTYPE;
} else if ("request".equals(scopeStr)) {
scope = Scope.REQUEST;
} else if ("session".equals(scopeStr)) {
scope = Scope.SESSION;
} else if ("singleton".equals(scopeStr)) {
scope = Scope.SINGLETON;
} else if ("thread".equals(scopeStr)) {
scope = Scope.THREAD;
}
if (StringUtils.isEmpty(name)) {
name = "default";
}
try {
Class classImpl = ClassLoaderUtil.loadClass(impl, this.getClass());
Class classType = classImpl;
if (StringUtils.isNotEmpty(type)) {
classType = ClassLoaderUtil.loadClass(type, this.getClass());
}
if ("true".equals(onlyStatic)) {
classImpl.getDeclaredClasses();
containerBuilder.injectStatics(new Class[]{classImpl});
} else {
if (containerBuilder.contains(classType, name)) {
Location loc = LocationUtils.getLocation(loadedBeans.get(classType.getName() + name));
if (this.throwExceptionOnDuplicateBeans) {
throw new ConfigurationException("Bean type " + classType + " with the name " + name + " has already been loaded by " + loc, child);
}
}
classImpl.getDeclaredConstructors();
LOG.debug("Loaded type: {} name: {} impl: {}", type, name, impl);
containerBuilder.factory(classType, name, new LocatableFactory(name, classType, classImpl, scope, childNode), scope);
}
loadedBeans.put(classType.getName() + name, child);
} catch (Throwable var23) {
...
}
LOG.debug("Unable to load optional class: {}", impl);
}
} else if ("constant".equals(nodeName)) {
...
}
props.setProperty(type, name, childNode);
} else if (nodeName.equals("unknown-handler-stack")) {
...
}
}
}
}
}
首先就是对<bean>结点信息进行解析,主要的信息type\name\class\scope等。然后调用:
containerBuilder.factory(classType, name, new LocatableFactory(name, classType, classImpl, scope, childNode), scope);
对于LocatableFactory不加以解释,暂时理解为工厂。scope就是范围的意思。
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 var3) {
throw new RuntimeException(var3);
}
}
public Class<? extends T> type() {
return factory.type();
}
public String toString() {
return (new LinkedHashMap<String, Object>() {
{
this.put("type", type);
this.put("name", name);
this.put("factory", factory);
}
}).toString();
}
};
return this.factory(Key.newInstance(type, name), internalFactory, scope);
}
终于看到了InternalFactory的实现了,其中create方法主要就是为工厂注入一个上下环境,我们进入create方法看看:
LocatableFactory
public T create(Context context) {
Object obj = context.getContainer().inject(this.implementation);
return obj;
}
这个我们在Container中提到过:inject()创建一个类的实例并进行对象的依赖注入操作。
那么接下来到了另外一个factory方法
return this.factory(Key.newInstance(type, name), internalFactory, scope);
private <T> ContainerBuilder factory(Key<T> key, InternalFactory<? extends T> factory, Scope scope) {
this.ensureNotCreated();
this.checkKey(key);
InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory);
this.factories.put(key, scopedFactory);
InternalFactory<T> callableFactory = this.createCallableFactory(key, scopedFactory);
if (EarlyInitializable.class.isAssignableFrom(factory.type())) {
this.earlyInitializableFactories.add(callableFactory);
} else if (scope == Scope.SINGLETON) {
this.singletonFactories.add(callableFactory);
}
return this;
}
InternalFactory又会被再次加工:
InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory);
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 (this.instance == null) {
this.instance = InitializableFactory.wrapIfNeeded(factory).create(context);
}
return this.instance;
}
}
public Class<? extends T> type() {
return factory.type();
}
public String toString() {
return factory.toString();
}
};
}
},
Scope是一个枚举类型,为工厂添加一个作用的范围,我们可以看到其中的SINGLETON也就是单例模式,返回的就是一个单例模式的工厂。这就是factories中存储的value的值了。