美文网首页
Dubbo SPI(三)

Dubbo SPI(三)

作者: outwar | 来源:发表于2018-08-31 09:30 被阅读0次

    ExtensionFactory

    上一篇大致讲了一下适配扩展的策略,可以看到对最后得到的适配实例还调用了injectExtension方法才提供了出去,这个方法绕不开ExtensionFactory类。并且在ExtensionLoader的构造方法上,当时也忽略了对ExtensionFactory类型的objectFactory的初始化。首先来看一下这个初始化代码:

    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    

    如果当前扩展接口不是ExtensionFactory(防止死循环)那么就会去得到ExtensionFactory的适配扩展实现。查看所有的实现类,很快就能找到AdaptiveExtensionFactory这个有Adaptive注解的适配类。

    @Adaptive
    public class AdaptiveExtensionFactory implements ExtensionFactory {
    //所有ExtensionFactory接口的普通扩展
    private final List<ExtensionFactory> factories;
    
    public AdaptiveExtensionFactory() {
        //得到ExtensionFactory的扩展加载对象
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        //遍历普通扩展,放到factories中
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }
    //得到扩展实例
    @Override
    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;
    }
    
    }
    

    ExtensionLoader#getSupportedExtensions

    public Set<String> getSupportedExtensions() {
        //普通扩展名字和类的关系
        Map<String, Class<?>> clazzes = getExtensionClasses();
        //返回所有的名字
        return Collections.unmodifiableSet(new TreeSet<String>(clazzes.keySet()));
    }
    

    ExtensionLoader#getExtension

    @SuppressWarnings("unchecked")
    public T getExtension(String name) {
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
            //true去拿默认扩展
        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;
    }
    

    ExtensionLoader#createExtension

    @SuppressWarnings("unchecked")
    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, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            //又出现了这个方法,接下来会讲
            injectExtension(instance);
            //缓存的包装扩展
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                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);
        }
    }
    

    ExtensionLoader#injectExtension

    最后看一下这个方法的源码,无论是提供出去包装扩展包装后的普通扩展还是适配扩展都会调用这个方法。其实质是通过ExtensionFactory·对扩展进行一些注入。

    private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
                //遍历所有public方法
                for (Method method : instance.getClass().getMethods()) {
                    //依次判断是否set开头,参数个数是否为1,是否public,
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        Class<?> pt = method.getParameterTypes()[0];
                        try {
                            //截取set后面的名字,首字符小写
                            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#getExtension

    现在最后的问题就是ExtensionFactory是如何得到指定类型和名字的对象的。我们刚刚看到了适配扩展的实现,但适配扩展仅仅是通过dubbo spi拿到所有的普通扩展类,然后调用它们的相同方法尝试去拿到,真正的实现在普通扩展中。

    SpiExtensionFactory

    public class SpiExtensionFactory implements ExtensionFactory {
    
        @Override
        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().isEmpty()) {
                    return loader.getAdaptiveExtension();
                }
            }
            return null;
        }
    
    }
    

    拿dubbo spi的实例。

    SpringExtensionFactory

    public class SpringExtensionFactory implements ExtensionFactory {
        private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
    
        private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
    
        //缓存Spring上下文
        public static void addApplicationContext(ApplicationContext context) {
            contexts.add(context);
        }
    
        public static void removeApplicationContext(ApplicationContext context) {
            contexts.remove(context);
        }
    
        // currently for test purpose
        public static void clearContexts() {
            contexts.clear();
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public <T> T getExtension(Class<T> type, String name) {
    
            //不支持dubbo spi的扩展对象
            if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
                return null;
            }
            //遍历所有的上下文判断是否有该bean name,然后再判断是否是该类型的实例
            for (ApplicationContext context : contexts) {
                if (context.containsBean(name)) {
                    Object bean = context.getBean(name);
                    if (type.isInstance(bean)) {
                        return (T) bean;
                    }
                }
            }
    
            logger.warn("No spring extension(bean) named:" + name + ", try to find an extension(bean) of type " + type.getName());
            //名字找不到就通过类型查找
            for (ApplicationContext context : contexts) {
                try {
                    return context.getBean(type);
                } catch (NoUniqueBeanDefinitionException multiBeanExe) {
                    throw multiBeanExe;
                } catch (NoSuchBeanDefinitionException noBeanExe) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
                    }
                }
            }
    
            logger.warn("No spring extension(bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");
    
            return null;
        }
    
    }
    

    对于如何注入spring上下文,可以查看addApplicationContext方法是在哪里调用的即可。

    相关文章

      网友评论

          本文标题:Dubbo SPI(三)

          本文链接:https://www.haomeiwen.com/subject/lqzjwftx.html