Dubbo-扩展机制ExtensionLoader

概述

Dubbo的一大特点就是扩展机制,在框架里很多地方都能看到它的身影。相比JDK SPI(Service Provider Interface)进行了加强,Dubbo SPI的扩展有几大特性:

  • 自动包装
  • 自动装配
  • 自动适配
  • 自动激活

ExtensionLoader

Dubbo SPI 主类,实现了扩展机制。Dubbo自己的各种扩展信息都放在各自的配置文件里,都放在各jar的META-INF/dubbo/接口全限定名,内容为:扩展名=扩展实现类的全限定名(多个实现类用换行符分隔)。比如META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol,内容为:

xxx=com.alibaba.xxx.XxxProtocol
xxx2=com.alibaba.xxx.Xxx2Protocol

getExtensionLoader

一类扩展接口由一个ExtensionLoader实例去维护,扩展加载器和扩展接口是一一对应的。

 /**
 * key:扩展接口
 * value:扩展加载器实例对象
 */
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();


 /**
 * 根据扩展接口,获得对应的扩展加载器,扩展加载器和扩展接口是一一对应的
 * 扩展接口,必须有@SPI注解
 *
 * @param type
 * @param <T>
 * @return
 */
@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    if (type == null)
        throw new IllegalArgumentException("Extension type == null");
    if (!type.isInterface()) {
        throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
    }
    // 扩展接口,必须有@SPI注解
    if (!withExtensionAnnotation(type)) {
        throw new IllegalArgumentException(
                        "Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class
                                        .getSimpleName() + " Annotation!");
    }

    ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    if (loader == null) {
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    }
    return loader;
}

getExtension

根据扩展名获取扩展实例,首先从缓存中取,没有命中就新创建。

/**
 * key:扩展名
 * value:扩展实现类的对象
 */
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
 
/**
 * 根据扩展名,返回对应的扩展实现类的对象
 * 只在这里会创建扩展对象实例,所以是需要才会创建对象
 *
 * @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;
}

loadFile

从配置文件中读取,扩展名和扩展实现类的映射关系。比如,RegistryFactory的扩展,放置在文件 `META-INF/dubbo/internal/com.alibaba.dubbo.registry.RegistryFactory` 中,loadFile() 方法会读取ClassPath下的所有这个文件,依次读取加载。

自动包装

如果某个扩展实现是一个包装器,拥有一个扩展接口为参数的构造函数,那么ExtensionLoader会将每个扩展实现都用这个包装器进行包装。

比如:

public class XxxProtocolWrapper implemenets Protocol {
    Protocol impl;

    public XxxProtocol(Protocol protocol) { impl = protocol; }

    // 接口方法做一个操作后,再调用extension的方法
    public void refer() {
        //... 一些操作
        impl.refer();
        // ... 一些操作
    }
}

ExtensionLoader中的实现,伪代码

 /**
 * 扩展接口的Wrapper类型
 */
private Set<Class<?>> cachedWrapperClasses;

Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
    // 如果扩展接口有Wrapper类型的扩展实现,就将扩展对象自动包装到Wrapper对象中
    // 此处为扩展自动包装特性
    for (Class<?> wrapperClass : wrapperClasses) {
        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
    }
}

自动装配

类似于Spring的IOC,依赖注入。如果某个扩展实现中有个属性是其他类型的扩展接口。ExtensionLoader通过setter方法判断,会自动设置这个属性。

/**
 * 此处为扩展自动装配特性
 * 为扩展实现类对象,设置依赖的属性
 *
 * @param instance
 * @return
 */
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())) {
                    // setter方法
                    Class<?> pt = method.getParameterTypes()[0];
                    try {
                        String property = method.getName().length() > 3 ?
                                        method.getName().substring(3, 4).toLowerCase() + method.getName()
                                                        .substring(4) :
                                        "";
                        // 从ExtensionFactory获得指定的属性
                        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;
}

ExtensionFactory

自动注入的属性是由ExtensionFactory完成的,在ExtensionLoader构造的时候设置了ExtensionFactory

private ExtensionLoader(Class<?> type) {
    this.type = type;
    // 是AdaptiveExtensionFactory扩展
    objectFactory = (type == ExtensionFactory.class ?
                    null :
                    ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

ExtensionFactory本身也有@SPI注解,也是扩展接口,分别是:

  • AdaptiveExtensionFactory:有@Adaptive注解,是ExtensionFactory自适配的扩展实现,会循环调用SpiExtensionFactory和SpringExtensionFactory的方法
  • SpiExtensionFactory:注入的是某个扩展接口的自适配实现
  • SpringExtensionFactory:注入的是Spring bean

AdaptiveExtensionFactory

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    /**
     * ExtensionFactory的所有扩展实现
     */
    private final List<ExtensionFactory> factories;

    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;
    }
}

SpiExtensionFactory

/**
 * 如果type是注解SPI,就返回这个扩展接口的自适应扩展实现
 *
 * @param type object type.
 * @param name object name.
 * @param <T>
 * @return
 */
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;
}

SpringExtensionFactory

/**
 * 从Spring容器中获取bean
 *
 * @param type object type.
 * @param name object name.
 * @param <T>
 * @return
 */
@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;
}

自动适配

如果某个扩展接口拥有@Adaptive注解,那么ExtensionLoader能够获取它的自适应扩展实现。自适配的意思是,在扩展接口的方法执行的时候根据url里的某个参数确定调用哪个扩展实现,也就是说在运行的时候才确定,可以做到根据url参数动态指定。

注:扩展接口必须要有@Adaptive注解,可以放在类上,也可以放在方法上。放在类上表示某个扩展实现是自适应的,放在方法上,Dubbo会自动生成代码来完成自适配功能。

private Class<?> getAdaptiveExtensionClass() {
    getExtensionClasses();

    // cachedAdaptiveClass是某个有@Adaptive的扩展实现
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    // 自动生成自适应的扩展实现类
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

/**
 * 自动生成类的字符串,然后编译成class
 *
 * @return
 */
private Class<?> createAdaptiveExtensionClass() {
    String code = createAdaptiveExtensionClassCode();
    ClassLoader classLoader = findClassLoader();
    // 获取Compiler的扩展实现,编译代码生成class
    com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader
                    .getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    return compiler.compile(code, classLoader);
}

自动激活

有些扩展接口,比如Filter等。经常是要由一些列的扩展实现组合使用的。为了简化使用,Dubbo提供了自动激活的功能,通过一个方法获取符合条件的扩展实现,由注解@Activate表示。

 

 参考:https://dubbo.gitbooks.io/dubbo-dev-book/SPI.html

转载于:https://my.oschina.net/cregu/blog/2223179

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值