4、DubboのSPIメカニズム分析3-DubboのIOC依存注入

11404 ワード

1、DubboのIOC例
@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が出力されるキーコードがあります.