资讯专栏INFORMATION COLUMN

dubbo扩展点的IOC

Zoom / 3123人阅读

摘要:属性上篇文章中,提到在获取扩展点接口对应的的时候,会执行私有构造函数。因为此时是,即当为时,即我们可以看出,所有非扩展点接口都会执行对应的实例的方法返回一个实例,即对象。

spring是如何获得容器中管理的类的

拿到applicationContext,就可以调用getBean方法来获得Spring的bean对象了

public class SpringContextUtil implements ApplicationContextAware {  
    // Spring应用上下文环境  
    private static ApplicationContext applicationContext;  
    /** 
     * 实现ApplicationContextAware接口的回调方法,设置上下文环境 
     *  
     * @param applicationContext 
     */  
    public void setApplicationContext(ApplicationContext applicationContext) {  
        SpringContextUtil.applicationContext = applicationContext;  
    }  
    /** 
     * @return ApplicationContext 
     */  
    public static ApplicationContext getApplicationContext() {  
        return applicationContext;  
    }  
    /** 
     * 获取对象 
     *  
     * @param name 
     * @return Object
     * @throws BeansException 
     */  
    public static Object getBean(String name) throws BeansException {  
        return applicationContext.getBean(name);  
    }  
}
dubbo扩展点的IOC 前文中,大致有提到一些有关IOC

第一点 在讲解ExtensionLoader源码的构造函数的时候,我们说过,每一个ExtensionLoader实例都有一个 objectFactory 属性,他是实现Ioc的关键;

第二点 相比较于JDK的SPI机制,dubbo的SPI机制支持扩展通过setter的方式来注入其他扩展点。

第三点 在调用ExtensionLoader的getExtension方法时,在获取了相应的class并创建了instance之后,通过injectExtension(intance)方法来通过setter的方式来注入其他扩展点。

第四点 loadFile函数解析SPI配置时,假如这个类带@Adaptive注解,缓存到cachedAdaptiveClass。

如何实现IOC -> ExtensionLoader的injectExtension方法源码

关键说明,

获取instance的所有方法,并解析以set方法开头的方法,例如setXxyy(Xxyy xxyy)。

拿到set方法的入参类型Xxyy、属性名xxyy。

执行objectFactory.getExtension(pt, property)拿到Xxyy对应的实例。

通过反射执行set方法,注入Xxyy对象。

    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;
    }
通过上面的方法,就可以将属性注入到instance中,实现自动装配(IOC)。下面我们来看一下 objectFactory.getExtension(pt, property)是如何工作的。
objectFactory属性
上篇文章中,提到在获取Container扩展点接口对应的ExtensionLoader的时候,会执行私有ExtensionLoader构造函数。
    private ExtensionLoader(Class type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
因为此时type是Container.class,即objectFactory = ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension();
当type为ExtensionFactory.class时,即 objectFactory = null.
我们可以看出,所有非ExtensionFactory.class扩展点接口都会执行ExtensionFactory对应的ExtensionLoader实例的getAdaptiveExtension()方法返回一个ExtensionFactory实例,即objectFactory对象。否则,objectFactory对象为null。
核心方法 -> ExtensionLoader的getAdaptiveExtension方法源码

getAdaptiveExtension 获取带有Adaptive注解的扩展实现类

createAdaptiveExtension()创建实例

injectExtension() 自动注入IOC

getAdaptiveExtensionClass() ---执行cachedAdaptiveClass对象的构造函数

getExtensionClasses() ---解析所有的扩展点实现

loadExtensionClasses() ---加载扩展类

loadFile() --- 从固定的文件路径,解析加载对应的扩展点实现【上一篇已经说过,这个地方会加载几种情形的扩展实现类,包括拿到cachedAdaptiveClass对象】

返回cachedAdaptiveClass --- 返回loadFile()方法中构造的cachedAdaptiveClass对象

执行 cachedAdaptiveClass.newInstance() ---执行AdaptiveExtensionFactory的构造函数

ExtensionFactory的实现类AdaptiveExtensionFactory带有Adaptive标签,另外两个实现类SpiExtensionFactory、SpringExtensionFactory就是正常的实现类,也是我们见的最多的那种扩展点实现类。

### AdaptiveExtensionFactory源码
关键说明,
1. factories属性,所有的非@Adaptive类的ExtensionFactory实例的集合,以后所有与ExtensionFactory打交道的操作都交给AdaptiveExtensionFactory,
2. injectExtension方法中,调用的 Object object = objectFactory.getExtension(pt, property);分别调用SpiExtensionFactory、SpringExtensionFactory两个实际的实现类。
/**
 * AdaptiveExtensionFactory
 *
 * @author william.liangf
 */
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    //所有的非@Adaptive类的ExtensionFactory实例的集合
    private final List factories;

    //因为ExtensionFactory对应的ExtensionLoader实例中缓存字段已经初始化好了,所以的ExtensionLoader的操作大都是从缓存中获取的数据
    public AdaptiveExtensionFactory() {
        //从缓存的static变量EXTENSION_LOADERS中拿到ExtensionFactory对应的ExtensionLoader实例
        ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List list = new ArrayList();
        //拿到loader中加载的普通的SPI扩展接口实现类的名称,spring与spi
        // adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
        // spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
        for (String name : loader.getSupportedExtensions()) {
            //根据名称创建对应的ExtensionFactory实例
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    public  T getExtension(Class type, String name) {
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}
SpringExtensionFactory源码
public class SpringExtensionFactory implements ExtensionFactory {

    private static final Set contexts = new ConcurrentHashSet();

    public static void addApplicationContext(ApplicationContext context) {
        contexts.add(context);
    }

    public static void removeApplicationContext(ApplicationContext context) {
        contexts.remove(context);
    }

    @SuppressWarnings("unchecked")
    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;
                }
            }
        }
        return null;
    }

}

是不是有一点熟悉的味道了啊,这也算是一个首尾呼应吧~

这一篇到时很快就写完了~ 下篇文章会讲解扩展点是如何实现AOP的。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69057.html

相关文章

  • Dubbo SPI机制和IOC

    摘要:要构建自适应实例,先要有自适应的实现类,实现类有两种方式一种通过配置文件,一种是通过是字节码的方式动态生成。 SPI机制 SPI,即(service provider interface)机制,有很多组件的实现,如日志、数据库访问等都是采用这样的方式,一般通用组件为了提升可扩展性,基于接口编程,将操作接口形成标准规范,但是可以开放多种扩展实现,这种做法也符合开闭设计原则,使组件具有可插...

    Scorpion 评论0 收藏0
  • 聊聊Dubbo - Dubbo扩展机制实战

    摘要:今天我想聊聊的另一个很棒的特性就是它的可扩展性。的扩展机制在的官网上,描述自己是一个高性能的框架。接下来的章节中我们会慢慢揭开扩展机制的神秘面纱。扩展扩展点的实现类。的定义在配置文件中可以看到文件中定义了个的扩展实现。 摘要: 在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架。今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性。 Dubbo的扩展机制 在Dub...

    techstay 评论0 收藏0
  • dubbo扩展点机制

    摘要:在中配置,以配置为例整个,最先使用的地方从里面读取这个配置使用接口的中获取具体的实现类中有两个值当主线程被外部终止时,会触发,执行的与方法通知下面的锁操作,主线程正常走完代码,并最终停止。 spring是如何启动容器的 常见的一种在本地使用main方法启动spring的方法 public static void main(String[] args) throws Except...

    Rindia 评论0 收藏0
  • Dubbo Spi机制

    摘要:为了实现在模块装配的时候,不在模块里写死代码,就需要一种服务发现机制。就提供了这样一种机制为某个接口寻找服务实现,有点类似思想,将装配的控制权移到代码之外。即接口文件的全类名。五示例遵循上述第一条第点,这里为接口文件,其中和为两个实现类。 一、Dubbo内核 Dubbo内核主要包含SPI、AOP、IOC、Compiler。 二、JDK的SPI 1.spi的设计目标: 面向对象的设计里...

    mrli2016 评论0 收藏0
  • 聊聊Dubbo - Dubbo扩展机制源码解析

    摘要:什么是类那什么样类的才是扩展机制中的类呢类是一个有复制构造函数的类,也是典型的装饰者模式。代码如下有一个参数是的复制构造函数有一个构造函数,参数是扩展点,所以它是一个扩展机制中的类。 摘要: 在Dubbo可扩展机制实战中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance。是不是觉得Dubbo的扩展机制很不错呀...

    lmxdawn 评论0 收藏0

发表评论

0条评论

Zoom

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<