Dubbo源码解读-Dubbo的容器启动

一直信奉世间万事万物的运行都有各自的规则。程序设计也有程序设计的原则,Linux有Linux的设计原则,Spring的设计原则是IoC和AOP。因此在阅读一个框架源码时要抓住这个框架设计的原则,这样才能容易理解。

Dubbo是阿里巴巴公司开源的一个分布式服务框架,主要功能有:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。

  • Container 服务运行容器
  • Provider 暴露服务的服务提供方
  • Registry 服务注册与发现的注册中心
  • Consumer 调用远程服务的服务消费方
  • Monitor 统计服务的调用次数和调用时间的监控中心

我们按Dubbo架构的模块各个击破。

  • Container Dubbo服务的启动都是从启动容器开始的,Dubbo服务的启动有三种方法: 1.使用Servlet容器运行; 2.自建Main方法运行(Spring容器); 3.使用Dubbo提供的Main方法类运行(Spring容器);

一般建议使用Dubbo提供的Main方法类运行,能够优雅关机。Main方法类里也是启动一个容器,这里就设计到SPI扩展机制了。首先咱们说说是SPI扩展机制。SPI(Service Provider Interface)是JDK内置的一直服务发现机制。比如JDBC中就是通过SPI机制提供给各数据库厂商调用实现接口。其实就是提供一个接口,在运行时动态添加实现。 下面我们说说Dubbo中怎么实现SPI的。在com.alibaba.dubbo.container.Main类中启动main方法。我会在代码注释中打上标识“① ②“可以根据标识定位查看具体的源码解析。

//com.alibaba.dubbo.container.Main
public class Main {

    public static final String CONTAINER_KEY = "dubbo.container";

    public static final String SHUTDOWN_HOOK_KEY = "dubbo.shutdown.hook";

    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    //创建ExtensionLoader对象,SPI扩展机制的实现就在这个类里。①解析ExtensionLoader.getExtensionLoader
    private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);

    private static final ReentrantLock LOCK = new ReentrantLock();

    private static final Condition STOP = LOCK.newCondition();

    public static void main(String[] args) {
        try {
            //查看是否有入参
            if (args == null || args.length == 0) {
                //没有的话就通过ConfigUtils.getProperty()方法去获取默认定的config②解析ExtensionLoader.getDefaultExtensionName 
                String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName());
                args = Constants.COMMA_SPLIT_PATTERN.split(config);
            }

            final List<Container> containers = new ArrayList<Container>();
            for (int i = 0; i < args.length; i++) {
              //通过上面获取的args从loader中获取上面已经加载的容器对象。比如这里是通过“spring”获取到容器对象SpringContainer
               containers.add(loader.getExtension(args[i]));
            }
            logger.info("Use container type(" + Arrays.toString(args) + ") to run dubbo serivce.");

            if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    public void run() {
                        for (Container container : containers) {
                            try {
                                container.stop();
                                logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!");
                            } catch (Throwable t) {
                                logger.error(t.getMessage(), t);
                            }
                            try {
                                LOCK.lock();
                                STOP.signal();
                            } finally {
                                LOCK.unlock();
                            }
                        }
                    }
                });
            }

            for (Container container : containers) {
                //启动容器,这里就是spring容器
                container.start();
                logger.info("Dubbo " + container.getClass().getSimpleName() + " started!");
            }
            System.out.println(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " Dubbo service server started!");
        } catch (RuntimeException e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            System.exit(1);
        }
        try {
            LOCK.lock();
            STOP.await();
        } catch (InterruptedException e) {
            logger.warn("Dubbo service server stopped, interrupted by other thread!", e);
        } finally {
            LOCK.unlock();
        }
    }

}
复制代码

①解析ExtensionLoader.getExtensionLoader Main类中初始化了一个ExtensionLoader对象,这个对象是通过 ExtensionLoader.getExtensionLoader(Container.class)初始化的。SPI机制的实现就在ExtensionLoader中体现的。

//com.alibaba.dubbo.common.extension.ExtensionLoader
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        //不能为空
        if (type == null)
            throw new IllegalArgumentException("Extension type == null");
        //type要是一个接口
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
        }
        //type上需要有SPI注解,比如Container上就有注解@SPI("spring"),有了这个注解才能实现SPI机制动态实现
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type(" + type +
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
        //EXTENSION_LOADERS是一个ConcurrentHashMap<Class<?>, ExtensionLoader<?>>()
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            //创建一个type的ExtensionLoader
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }
复制代码

②解析ExtensionLoader.getDefaultExtensionName

//获取默认的扩展名
public String getDefaultExtensionName() {
        getExtensionClasses();
        //cachedDefaultName是个全局变量,在loadExtensionClasses方法中赋值
        return cachedDefaultName;
    }
    
private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    //加载扩展类
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
    
// synchronized in getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
        //获取默认的注解,这里是@SPI("spring")
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            //获取注解值这里是“spring”
            String value = defaultAnnotation.value();
            if (value != null && (value = value.trim()).length() > 0) {
                //正则匹配注解值,通过“,”分隔符
                String[] names = NAME_SEPARATOR.split(value);
                //如果注解的字段大于1,就抛出异常,也就是说@SPI注解中只可以有一个值
                if (names.length > 1) {
                    throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                            + ": " + Arrays.toString(names));
                }
                //给cacheDefaultName赋值,这里赋值为“spring”
                if (names.length == 1) cachedDefaultName = names[0];
            }
        }

        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        //加载不同路径下的类放到extensionClasses,具体细节可以看loadFile方法
        loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        loadFile(extensionClasses, DUBBO_DIRECTORY);
        loadFile(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }
复制代码

META-INF.dubbo.internal下有个配置文件,里面的配置是

spring=com.alibaba.dubbo.container.spring.SpringContainer
复制代码

因此可以通过"spring"扩展实现的类是com.alibaba.dubbo.container.spring.SpringContainer。

这里只是简单分析Dubbo的一种启动方式,不是很深入,抛砖引玉,大家可以继续深入的研究一下。

转载于:https://juejin.im/post/5aaa16296fb9a028e52d8fa5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值