4、DubboのSPIメカニズム分析3-DubboのIOC依存注入
1、DubboのIOC例
2、DubboのIOCが必要とするExtensionFactory
SpringのIOCでは、生成したbeanに依存を注入し、contextを呼び出す.getBean(name)は注入するbeanを得る.DubboのIOCは、ExtensionFactoryタイプの変数objectFactoryを介してdubboからbean、コアコード
ここでのgetExtensionLoader()の詳細な解析については、DubboのSPIメカニズム1-SPI単純解析を参照してください.
getExtensionClasses()メソッドの詳細な解析は、DubboのSPIメカニズム1-SPI単純解析を参照してください.
3、DubboのIOCソース分析
ここで適応拡張を得るには,DubboのSPI機構解析2−Adaptiveの詳細な解を参照できる.
4、テストはURL依存注入に合格する
上記コード出力spring cloudは、Dubbo AdaptiveExtのインスタンスを作成して注入依存を与えるときにinjectExtension(instance)を呼び出し、@Adaptive表記のクラスがないため、Dubbo自身が適応拡張エージェントクラスClassを生成する必要があり、生成過程は、DubboのSPIメカニズム解析2-Adaptive詳細を参照することができる.生成されたエージェントクラスには、urlにこのtパラメータがあるため、最後にcloudに対応するSpringCloudAdaptiveExtのechoメソッドが呼び出され、spring cloudが出力されるキーコードがあります.
@Test
public void test1(){
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
URL url = URL.valueOf("test://localhost/test");
adaptiveExtension.echo("d", url);
}
public class DubboAdaptiveExt implements AdaptiveExt {
// dubbo AdaptiveExt
private AdaptiveExt adaptiveExt;
public void setAdaptiveExt(AdaptiveExt adaptiveExt) {
this.adaptiveExt = adaptiveExt;
}
@Override
public String echo(String msg, URL url) {
System.out.println(this.adaptiveExt.echo(msg, url));
return "dubbo";
}
}
// ThriftAdaptiveExt @Adaptive
@Adaptive
public class ThriftAdaptiveExt implements AdaptiveExt {
@Override
public String echo(String msg, URL url) {
return "thrift";
}
}
2、DubboのIOCが必要とするExtensionFactory
SpringのIOCでは、生成したbeanに依存を注入し、contextを呼び出す.getBean(name)は注入するbeanを得る.DubboのIOCは、ExtensionFactoryタイプの変数objectFactoryを介してdubboからbean、コアコード
objectFactory.getExtension(pt, property)
を取得する.次にobjectFactoryの作成手順を分析する.objectFactoryにはSpringExtensionFactory SpiExtensionFactory
が必要である.まずExtenionFactoryの実装クラスを見てみましょう.以下の図です.次に、objectFactoryの生成過程をソースコードにより分析する.ここでのgetExtensionLoader()の詳細な解析については、DubboのSPIメカニズム1-SPI単純解析を参照してください.
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
public static ExtensionLoader getExtensionLoader(Class type) {
// ,
// ExtensionLoader
ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
if (loader == null) {
// , ,
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
}
return loader;
}
private ExtensionLoader(Class> type) {
this.type = type;
// type AdaptiveExt.class, , SpiExtensionFactory
// SpringExtensionFactory
objectFactory = (type == ExtensionFactory.class ? null :
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// , ExtensionFactory
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
//
}
}
}
}
}
return (T) instance;
}
private T createAdaptiveExtension() {
try {
// 3 :1 Class ,2 ,3
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
//
}
}
getExtensionClasses()メソッドの詳細な解析は、DubboのSPIメカニズム1-SPI単純解析を参照してください.
private Class> getAdaptiveExtensionClass() {
// , ExtensionFactory , 3 ,
// META-INF/dubbo/internal/, , , AdaptiveExtensionFactory
// @Adaptive , , ExtensionFactory
getExtensionClasses();
// @Adaptive , cachedAdaptiveClass ,
if (cachedAdaptiveClass != null) {
// ,cachedAdaptiveClass = AdaptiveExtensionFactory.class
return cachedAdaptiveClass;
}
//
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
1 :
// AdaptiveExtensionFactory @Adaptive
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
2 :
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
// getAdaptiveExtensionClass(), AdaptiveExtensionFactory, newInstance
//
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
// SpringExtensionFactory SpiExtensionFactory
private final List factories;
public AdaptiveExtensionFactory() {
ExtensionLoader loader =
ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List list = new ArrayList();
for (String name : loader.getSupportedExtensions()) {
// SpringExtensionFactory SpiExtensionFactory list
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
}
3、DubboのIOCソース分析
// , ExtensionFactory objectFactory, list,
// list SpringExtensionFactory SpiExtensionFactory ,Dubbo IOC bean
//
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
public T getExtension(String name) {
//
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
private T createExtension(String name) {
// , “ ” “ ”
// dubbo, getAdaptiveExtension ,
// com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExt
Class> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
// ,
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
// DubboAdaptiveExt ,
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//
injectExtension(instance);
return instance;
}
}
private T injectExtension(T instance) {
// ,
// objectFactory , SpringExtensionFactory SpiExtensionFactory
if (objectFactory != null) {
// DubboAdaptiveExt , set 1 , public
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
// , AdaptiveExt.class
Class> pt = method.getParameterTypes()[0];
// , adaptiveExt
String property =
method.getName().length() > 3 ?
method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
// AdaptiveExt.class adaptiveExt
Object object = objectFactory.getExtension(pt, property);
//
if (object != null) {
method.invoke(instance, object);
}
}
}
}
return instance;
}
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List factories;
@Override
public T getExtension(Class type, String name) {
// factory ExtensionFactory, SpiExtensionFactory , Spring
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
ここで適応拡張を得るには,DubboのSPI機構解析2−Adaptiveの詳細な解を参照できる.
public class SpiExtensionFactory implements ExtensionFactory {
@Override
public T getExtension(Class type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(type);
if (!loader.getSupportedExtensions().isEmpty()) {
// SpiExtensionFactory , getAdaptiveExtension() ,
// name, ThriftAdaptiveExt
return loader.getAdaptiveExtension();
}
}
return null;
}
}
public class SpringExtensionFactory implements ExtensionFactory {
// Spring ,
@Override
public T getExtension(Class type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
for (ApplicationContext context : contexts) {
try {
return context.getBean(type);
}
}
return null;
}
}
// :thrift
@Test
public void test1(){
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
URL url = URL.valueOf("test://localhost/test");
adaptiveExtension.echo("d", url);
}
4、テストはURL依存注入に合格する
/**
* URL , ThriftAdaptiveExt , AdaptiveExt @Adaptive("t")
*/
@Test
public void test5(){
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
Map map = new HashMap<>();
// t key @Adaptive("t") ,
map.put("t", "cloud");
URL url = new URL("", "", 1, map);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
adaptiveExtension.echo(" ", url);
}
上記コード出力spring cloudは、Dubbo AdaptiveExtのインスタンスを作成して注入依存を与えるときにinjectExtension(instance)を呼び出し、@Adaptive表記のクラスがないため、Dubbo自身が適応拡張エージェントクラスClassを生成する必要があり、生成過程は、DubboのSPIメカニズム解析2-Adaptive詳細を参照することができる.生成されたエージェントクラスには、urlにこのtパラメータがあるため、最後にcloudに対応するSpringCloudAdaptiveExtのechoメソッドが呼び出され、spring cloudが出力されるキーコードがあります.