1. 程式人生 > >深入dubbo核心(3):dubbo的IOC機制

深入dubbo核心(3):dubbo的IOC機制

當@Adaptive註解沒有註解在擴充套件點實現類上,而是在擴充套件點實現類的方法上的時候則會生成一個<擴充套件點介面名>$Adpative的代理類。

 private Class<?> createAdaptiveExtensionClass() {
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return
compiler.compile(code, classLoader);
}
  • createAdaptiveExtensionClassCode()會生成一個模板程式碼
public class <擴充套件點介面名>$Adpative implements <擴充套件點介面> {
public <有@Adaptive註解的介面方法>(<方法引數>) {
if(是否有URL型別方法引數?) 使用該URL引數
else if(是否有方法型別上有URL屬性) 使用該URL屬性
# <else
在載入擴充套件點生成自適應擴充套件點類時拋異常,即載入擴充套件點失敗!>
if(獲取的URL == null) {
throw new IllegalArgumentException("url == null");
}
根據@Adaptive註解上宣告的Key的順序,從URL獲致Value,作為實際擴充套件點名。
如URL沒有Value,則使用預設擴充套件點實現。如沒有擴充套件點, throw new IllegalStateException("Fail to get extension");
在擴充套件點實現呼叫該方法,並返回結果。
}
public
<有@Adaptive註解的介面方法>(<方法引數>) {
throw new UnsupportedOperationException("is not adaptive method!");
}
}
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null) {
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
}
if (arg0.getUrl() == null) {
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
}
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null) {
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
}
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) {
throw new IllegalArgumentException("url == null");
}
com.alibaba.dubbo.common.URL url = arg1;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null) {
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
}
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
}

然後會接著通過getExtension(name)獲得指定名稱的擴充套件點的例項。

  • getExtension(name)
/**
* 返回指定名字的擴充套件。如果指定名字的擴充套件不存在,則拋異常 {@link IllegalStateException}.
*
* @param name
* @return
*/

@SuppressWarnings("unchecked")
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
return getDefaultExtension();
}
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}

這裡巧妙的使用了快取,單例,和高併發。接下來我會單獨分析dubbo的spi中是如何解決高併發處理的。

  • createExtension()
private T createExtension(String name) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
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);
}
}

在建立擴充套件點例項的時候,同樣是使用getExtensionClasses()獲取他的class物件,在這裡有一個非常重要的方法就是injectExtension().這個方法是dubbo進行IOC和AOP的地方。

    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())) {
Class<?> pt = method.getParameterTypes()[0];
try {
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
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;
}

上次我們說到了objectFactory是dubbo用於IOC和AOP的工廠,而他真正產生作用的地方就是injectExtension(T),我們可以注意到objectFactory實際上就是ExtensionFactory的自適應擴充套件點。在這裡我們要首先介紹一下ExtensionFactory的三個實現類。

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions()) {
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}

這是一個典型的介面卡模式。通過介面卡獲得另外的兩個ExtensionFactory實現類。

public class SpiExtensionFactory implements ExtensionFactory {
public <T> T getExtension(Class<T> type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
if (loader.getSupportedExtensions().size() > 0) {
return loader.getAdaptiveExtension();
}
}
return null;
}
}

SpiExtensionFactory負責載入擴充套件點的自適應擴充套件點物件。

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)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
return null;
}
}

通過spring容器載入擴充套件點例項。

  • 總結以上程式碼
    通過以上程式碼分析可以看出來,dubbo的ExtensionFactory維護了兩套bean的管理容器SpringExtensionFactory和SpiExtensionFactory,通過介面卡模式使用AdaptiveExtensionFactoy來統一管理這兩種容器。而objectFactoty實際上就是
    AdaptiveExtensionFactoy適配工廠類。所以在dubbo一個內部的bean的注入一定是通過SpiExtensionFactory實現的。而類似於服務的釋出則交由spring統一管理.