webwork的IOC(基于2.1.X版本)
webwork的ioc其實在webwork中使用起來挺方便的,雖然其功能不算強大,但是已經能很好的滿足我們一般的需要了,就算我們使用spring 的ioc,如果不使用特別的功能,其一般我們也是基于接口,然后有個set方法,通過set來注入,沒有太多的區別,不同的是webwork的ioc需要依賴xwork,而spring卻是依賴spring這個容器。
webwork的ioc是怎么進行注入的了,我們從代碼中進行分析:
首先看看攔截器的代碼:
public class ComponentInterceptor extends AroundInterceptor {
//~ Static fields/initializers /////////////////////////////////////////////
public static final String COMPONENT_MANAGER = "com.opensymphony.xwork.interceptor.component.ComponentManager";
//~ Methods ////////////////////////////////////////////////////////////////
protected void after(ActionInvocation dispatcher, String result) throws Exception {
}
protected void before(ActionInvocation dispatcher) throws Exception {
ComponentManager container = (ComponentManager) ActionContext.getContext().get(COMPONENT_MANAGER);
if (container != null) {
container.initializeObject(dispatcher.getAction());
}
}
}
主要的代碼用黑體標注出來了,container實際就是組件管理器,這里是一個ComponentManager接口的實現 DefaultComponentManager,然后調用了該類的方法initializeObject(dispatcher.getAction ());而dispatcher.getAction()實際就是所調用的action對象,我們再來看看 DefaultComponentManager做了什么。
public void initializeObject(Object obj) {
loadResource(obj, obj.getClass(), this);
}
private Class loadResource(Object resource, Class clazz, DefaultComponentManager dcm) {
// ~由此來判斷是否要進行依賴注入
boolean resourceNotLoaded = !dcm.loadOrder.contains(resource);
if (resourceNotLoaded) {
Map resources = getResourceDependencies(clazz);
for (Iterator iterator = resources.entrySet().iterator();
iterator.hasNext();) {
Map.Entry mapEntry = (Map.Entry) iterator.next();
Class depResource = (Class) mapEntry.getKey();
DefaultComponentManager newDcm = (DefaultComponentManager) mapEntry.getValue();
try {
ResourceEnablerPair pair = setupAndOptionallyCreateResource(newDcm, depResource);
setupResource(resource, pair.enabler, pair.resource);
} catch (Exception e) {
e.printStackTrace();
if (log.isDebugEnabled()) {
log.debug("Error loading or setting up resource: " + resources.getClass().getName(), e);
}
}
}
dcm.alreadyLoaded.add(clazz);
if (resource instanceof Initializable) {
Initializable initializable = (Initializable) resource;
initializable.init();
}
dcm.resourceInstances.put(clazz, resource);
dcm.loadOrder.add(resource);
}
// now return this class's enabler
Class enabler = (Class) dcm.enablers2.get(clazz);
return enabler;
}
private Map getResourceDependencies(Class resourceClass) {
List interfaces = new ArrayList();
//~ 將所有的interface放入interfaces鏈表中
addAllInterfaces(resourceClass, interfaces);
Map dependencies = new HashMap();
for (Iterator iterator = interfaces.iterator(); iterator.hasNext();) {
Class anInterface = (Class) iterator.next();
DefaultComponentManager dcm = this;
while (dcm != null) {
Class possibleResource = (Class) dcm.enablers.get(anInterface);
if (possibleResource != null) {
dependencies.put(possibleResource, dcm);
break;
}
dcm = dcm.fallback;
}
}
return dependencies;
}
private void addAllInterfaces(Class clazz, List allInterfaces) {
if (clazz == null) {
return;
}
Class[] interfaces = clazz.getInterfaces();
allInterfaces.addAll(Arrays.asList(interfaces));
addAllInterfaces(clazz.getSuperclass(), allInterfaces);
}
重要的代碼都用黑體進行了標注,方法initializeObject中所調用的loadResource(obj, obj.getClass(), this);就執行了查找接口,并注入接口實現類整個過程。
loadResource首先調用了getResourceDependencies(clazz);而getResourceDependencies又調用了addAllInterfaces(resourceClass, interfaces);addAllInterfaces作用就是取得這個類包括這個類的父類的所有實現的接口,而getResourceDependencies方法就是對這個接口進行過濾,返回只是在配置中有的接口。setupAndOptionallyCreateResource(newDcm, depResource);進行的就是創建這些接口的實現類的對象,這個代碼的內容如下:
private ResourceEnablerPair setupAndOptionallyCreateResource(DefaultComponentManager newDcm, Class depResource) throws Exception {
ResourceEnablerPair pair = new ResourceEnablerPair();
Object newResource = newDcm.resourceInstances.get(depResource);
if (newResource == null) {
newResource = ObjectFactory.getObjectFactory().buildBean(depResource);
}
pair.resource = newResource;
Class enabler = loadResource(newResource, depResource, newDcm);
pair.enabler = enabler;
return pair;
}
因為準備創建出來的接口實現類對象的接口可能又實現了其他的接口,因此再調用了loadResource(newResource, depResource, newDcm)。對象創建了,然后就是注入這個對象,setupResource(resource, pair.enabler, pair.resource)就是起這個作用的。代碼如下:
private void setupResource(Object resource, Class enabler, Object newResource) {
if (enabler == null) {
return;
}
try {
enabler.getMethods()[0].invoke(resource, new Object[] {newResource});
} catch (Exception e) {
e.printStackTrace();
if (log.isDebugEnabled()) {
log.debug("Error invoking method for resource: " + resource.getClass().getName(), e);
}
}
}
每個接口只有一個set方法,通過反射機制調用這個方法將創建出來的接口實現對象注入進去。整個IOC就完成了。