zoukankan      html  css  js  c++  java
  • Dubbo微容器(Cooma)详解

    Dubbo微容器详解

    ExtensionLoader

    ExtensionLoader是Dubbo中的SPI的实现方法,它是Dubbo框架的微容器,也为框架提供各种组件的扩展点

    三种注解

    • SPI
    • Adaptive
    • Activate

    How to Work

    先看Java自带SPI(Service Provider Interface)

    • ServiceLoader是一个简单的服务提供者加载工具
      (A simple service-provider loading facility)

    • since JDK 1.6

    • 简单的例子

      jdk spi

    • 一个关于Car的Interface

    public interface Car {
        void run();
    }
    
    • 2个Car是具体实现
    public class RacingCar implements Car {
        @Override
        public void run() {
            	System.out.println("RacingCar Running...");
        	}
    }
    
    public class SportCar implements Car {
        @Override
        public void run() {
            	System.out.println("SportCar Running...");
        	}
    }
    
    • 调用类
    public class Main {
        public static void main(String[] agrs){
            ServiceLoader<Car> serviceLoader =  ServiceLoader.load(Car.class);
            serviceLoader.forEach(car -> {
                car.run();
            });
        }
    }
    
    • META-INF/services/com.youzan.soa.Car 内容

      com.youzan.soa.RacingCar
      com.youzan.soa.SportCar
      
    • 工程目录结构

    Dubbo SPI机制

    Dubbo SPI机制Java的SPI机制相似,又比它多了一些功能

    1. 提供注解方式,可以方便的扩展实现
    2. 依赖注入功能

    如何实现

    • 构造一个ExtensionLoader实例
    ExtensionLoader<SimpleExt> extensionLoader = ExtensionLoader.getExtensionLoader(SimpleExt.class);
    
    • 流程

    • 结合源码分析

    private Map<String, Class<?>> loadExtensionClasses() {
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if(defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if(value != null && (value = value.trim()).length() > 0) {
                //...省略次要部分代码
            }
        }
    
        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        loadFile(extensionClasses, DUBBO_DIRECTORY);
        loadFile(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }
    

    真正加载SpiExtensionFactory和AdaptiveExtensionFactory的是loadExtensionClasses方法,干活是loadFile方法。loadExtensionClasses会去查找三个路径下对应的工厂类扩展点

    在构造AdaptiveExtensionFactory的ExtensionLoader实例并不需要加载依赖
    也就是AdaptiveExtensionFactory的ExtensionLoader实例objectFactory=null,而SimpleExt的ExtensionLoader实例objectFactory是AdaptiveExtensionFactory。

    private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
    private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
                //... 省略部分代码代码
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    } 
    

    获取扩展点

    • 调用
    	SimpleExt simpleExt = extensionLoader.getExtension("impl1");
    
    • 流程

    • 源码分析

    createExtension方法

    private T createExtension(String name) {
        Class<?> clazz = getExtensionClasses().get(name);
        //...省略
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);
            //...省略
            return instance;
        } catch (Throwable t) {
            //...省略
        }
    }
    

    createExtension是创建扩展点的入口,先通过getExtensionClasses加载三个路径下对应的扩展类,然后调用injectExtension注入依赖

    详细分析injectExtension方法

    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) {
                            //...省略
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }
    

    因为SimpleExt的ExtensionLoader实例objectFactory是AdaptiveExtensionFactory,所以if分支的代码会执行。SimpleExt实例impl1有依赖的属性dao如下, injectExtension是通过set方法注入依赖。 如果此时依赖没有创建好,通过objectFactory.getExtension递归创建扩展点

    public class SimpleExtImpl1 implements SimpleExt {
        public Dao dao;  
        public void setDao(Dao dao){
            this.dao = dao;
        }
        public String echo(URL url, String s) {
            return "Ext6Impl1-echo-" + ext1.echo(url, s);
        }  
    }
    
    • objectFactory.getExtension, objectFactory的实现类是AdaptiveExtensionFactory, getExtension方法是一个入口,最终干活的是在factories中即是SpiExtensionFactory
    	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.getExtension的内部调用ExtensionLoader.getExtensionLoader递归加载依赖
    	public class SpiExtensionFactory implements ExtensionFactory {
    	    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;
    	    }
    	}
    

    至此SimpleExt的扩展点及其依赖都已经加载完毕,是不是和spring的依赖注入有点相似,简易版本的Spring依赖管理

    • 下一篇讲介绍Dubbo微容器的启动
  • 相关阅读:
    centos安装vsftp
    php利用soap实现webservice 和利用soap调用其他语言的webservice
    php连接redis数据库 操作redis任务队列
    shopnc编译安装IM服务器node.js
    centos6.5 64位 yum install nginx的默认安装路径
    安装nfs服务器
    php扩展redis,编译安装redis服务
    x86_64编译JPEG遇到Invalid configuration `x86_64-unknown-linux-gnu'
    shopnc nginx优化配置文件
    nginx支持flv MP4 扩展nginx_mod_h264_streaming,nginx-rtmp-module-master,yamdi
  • 原文地址:https://www.cnblogs.com/oldtrafford/p/6773551.html
Copyright © 2011-2022 走看看