“載營魄抱一,能無離乎?
專氣致柔,能如嬰兒乎?
滌除玄覽,能無疵乎?
愛民治國,能無以智乎?
天門開闔,能為雌乎?
明白四達(dá),能無為乎?
生之畜之,生而不有,為而不恃,長而不宰,是謂玄德?!?sup>[1]
Spring從誕生至今,ioc和aop一直都是其靈魂所在,至今我們使用spring依然依賴這兩大特性:依賴注入(ioc)、面向切面編程(aop)。從設(shè)計(jì)模式上來講,卻極其簡單,無外乎工廠模式和代理模式。
今天我們從dubbo的內(nèi)核源碼入手,來看看ioc和aop是如何影響著dubbo的框架設(shè)計(jì)。
ioc在dubbo中的應(yīng)用
dubbo的ioc主要體現(xiàn)在dubbo擴(kuò)展點(diǎn)加載的環(huán)節(jié),T injectExtension(T instance)方法中。該方法只在三個(gè)地方被使用:
createAdaptiveExtension()
--injectExtension((T) getAdaptiveExtensionClass().newInstance()) //為創(chuàng)建好的AdaptiveExtensionClass實(shí)例進(jìn)行屬性注入
createExtension(String name)
--injectExtension(instance) //為創(chuàng)建好的Extension實(shí)例進(jìn)行屬性注入
--injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) //為創(chuàng)建好的wrapperClass實(shí)例進(jìn)行屬性注入
ExtensionLoader:
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {//一個(gè)參數(shù)的public的setXXX(T param)方法.例如,setName(String name)
Class<?> pt = method.getParameterTypes()[0];//參數(shù)param的類型T,eg.String
try {
String property = method.getName().length() > 3
? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";//獲取屬性名XXX, eg.name
Object object = objectFactory.getExtension(pt, property);//實(shí)例化參數(shù)
if (object != null) {
//執(zhí)行instance.method(object)方法,這里就是執(zhí)行instance的setter方法,進(jìn)行setter注入
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName() + " of interface "
+ type.getName() + ": " + e.getMessage(),
e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
整個(gè)方法的作用就是通過instance對象實(shí)例的setter方法為instance的屬性賦值,完成setter注入,即IOC的最經(jīng)典的注入方式。
詳細(xì)步驟:
- 獲取instance的setter方法,通過setter方法獲取屬性名稱property和屬性類型pt(即paramType的簡寫)
- 使用objectFactory創(chuàng)建一個(gè)property名稱(類型為pt)的對象實(shí)例
- 執(zhí)行instance的setter方法,注入property實(shí)例
其中,比較重要的就是:Object object = objectFactory.getExtension(pt, property);這個(gè)方法。其中的objectFactory=AdaptiveExtensionFactory實(shí)例,其屬性factories = [SpringExtensionFactory實(shí)例, SpiExtensionFactory實(shí)例]。
看一下源碼:
private final List<ExtensionFactory> factories;
public <T> T getExtension(Class<T> type, String name) {
/**
* 先調(diào)用SpiExtensionFactory來實(shí)例化;
* 如果不行,再使用SpringExtensionFactory來實(shí)例化
*/
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
SpiExtensionFactory:
public class SpiExtensionFactory implements ExtensionFactory {
public <T> T getExtension(Class<T> type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {//type是接口且必須具有@SPI注解
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
if (loader.getSupportedExtensions().size() > 0) {//獲取type的所有ExtensionClasses實(shí)現(xiàn)的key
return loader.getAdaptiveExtension();//獲取type的裝飾類,如果有@Adaptive注解的類,則返回該類的實(shí)例,否則返回一個(gè)動(dòng)態(tài)代理類的實(shí)例(例如Protocol$Adpative的實(shí)例)
}
}
return null;
}
}
從這里我們可以看出dubbo-SPI的另外一個(gè)好處:可以為SPI實(shí)現(xiàn)類注入SPI的裝飾類或動(dòng)態(tài)代理類。
SpringExtensionFactory:
public class SpringExtensionFactory implements ExtensionFactory {
private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
public static void addApplicationContext(ApplicationContext context) {
contexts.add(context);
}
public static void removeApplicationContext(ApplicationContext context) {
contexts.remove(context);
}
@SuppressWarnings("unchecked")
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {//該context是否包含name的bean
Object bean = context.getBean(name);//獲取name的bean,如果是懶加載或多例的bean,此時(shí)會實(shí)例化name的bean
if (type.isInstance(bean)) {//如果obj的類型是type或其子類,與instanceof相同
return (T) bean;
}
}
}
return null;
}
}
aop在dubbo中的應(yīng)用
dubbo在獲取擴(kuò)展點(diǎn)時(shí),會有如下調(diào)用:
final Protocol dubboProtocol = loader.getExtension("dubbo");
調(diào)用層級:
ExtensionLoader<T>.getExtension()
--createExtension(String name)
----getExtensionClasses().get(name)//獲取擴(kuò)展類
------loadExtensionClasses()
--------loadFile(Map<String, Class<?>> extensionClasses, String dir)
----injectExtension(instance);//ioc
----wrapper包裝;//aop
createExtension(String name),該方法源碼如下:
private T createExtension(String name) {
/** 從cachedClasses緩存中獲取所有的實(shí)現(xiàn)類map,之后通過name獲取到對應(yīng)的實(shí)現(xiàn)類的Class對象 */
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
/** 從EXTENSION_INSTANCES緩存中獲取對應(yīng)的實(shí)現(xiàn)類的Class對象,如果沒有,直接創(chuàng)建,之后放入緩存 */
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type
+ ") could not be instantiated: " + t.getMessage(),
t);
}
}
這里,先給出META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol內(nèi)容:
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper和com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper,這兩個(gè)類不含有@Adaptive注解且具有含有Protocol的單參構(gòu)造器,符合這樣條件的會被列入AOP增強(qiáng)類。放置在loader的私有屬性cachedWrapperClasses中。
此時(shí)的loader:
- Class<?> type = interface com.alibaba.dubbo.rpc.Protocol
- ExtensionFactory objectFactory = AdaptiveExtensionFactory(適配類)
factories = [SpringExtensionFactory實(shí)例, SpiExtensionFactory實(shí)例] - cachedWrapperClasses = [class ProtocolListenerWrapper, class ProtocolFilterWrapper]
再來看createExtension(String name)中的紅色部分,就是今天的重點(diǎn)AOP。如上所講,我在cachedWrapperClasses中緩存了兩個(gè)AOP增強(qiáng)類:class ProtocolListenerWrapper和class ProtocolFilterWrapper。
首先是獲取ProtocolListenerWrapper的單參構(gòu)造器,然后創(chuàng)建ProtocolListenerWrapper實(shí)例,最后完成對ProtocolListenerWrapper實(shí)例進(jìn)行屬性注入,注意此時(shí)的instance=ProtocolListenerWrapper實(shí)例,而不再是之前的DubboProtocol實(shí)例了。之后使用ProtocolFilterWrapper以同樣的方式進(jìn)行包裝,只是此時(shí)ProtocolFilterWrapper包裝的是ProtocolListenerWrapper實(shí)例。
-
老子《道德經(jīng)》第十章,老子故里,中國鹿邑。 ?