前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >dubbo(三)服务运行容器Container

dubbo(三)服务运行容器Container

作者头像
虞大大
发布2020-09-24 15:33:45
1.2K0
发布2020-09-24 15:33:45
举报
文章被收录于专栏:码云大作战码云大作战

一、服务运行容器-Container

Dubbo中的其中一个角色,服务运行容器Container。他是一个独立的容器,如果项目比较轻,没用到Web特性,因此不想用Tomcat等Web容器,则可以使用Main方法加载Spring容器。

· Container容器启动原理

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {            //如果未配置容器实现,则默认使用Spring容器            if (args == null || args.length == 0) {
                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++) {                //对配置的容器进行遍历与加载,通过SPI加载SpringContainer                containers.add(loader.getExtension(args[i]));
}            //...            for (Container container : containers) {                //启动SpringContainer容器                container.start();
                logger.info("Dubbo " + container.getClass().getSimpleName() + " started!");
            }
            //...
    }
}

Container实现类有很多种,但是这里默认通过SPI加载的是SpringContainer容器,最后通过SpringContainer.start()读取配置加载bean,启动容器。

代码语言:javascript
复制
public void start() {    //配置文件路径 写死的 = classpath*:META-INF/spring/*.xml    String configPath = ConfigUtils.getProperty(SPRING_CONFIG);
    if (configPath == null || configPath.length() == 0) {
        configPath = DEFAULT_SPRING_CONFIG;
    }
    context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"), false);
    context.addApplicationListener(new DubboApplicationListener());    //注册优雅停机配置dubbo-container-shutdown-hook    context.registerShutdownHook();
代码语言:javascript
复制
    //通过context加载bean
代码语言:javascript
复制
    context.refresh();
    context.start();
}

· Container容器停止原理

通过kill PID关闭容器时,如果注册了dubbo-container-shutdown-hook则会进入以下代码优雅停机。

代码语言:javascript
复制
public static void main(String[] args) {
    //...
        if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) {
            Runtime.getRuntime().addShutdownHook(new Thread("dubbo-container-shutdown-hook") {
                @Override
                public void run() {
                    for (Container container : containers) {
                        try {                            //调用SpringContainer.stop停止容器                            container.stop();
                        } catch (Throwable t) {
                            logger.error(t.getMessage(), t);
                        }
                        try {
                            LOCK.lock();
                            STOP.signal();
                        } finally {
                            LOCK.unlock();
                        }
                    }
                }
            });
        }
       //...
}

通过SpringContainer.stop()销毁bean和关闭容器。

原理:

(1)服务提供方

停止时,先标记为不接受新请求,新请求过来时直接报错,让客户端重试其他机器。然后检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,如果超时则强制关闭。

(2)服务消费方

停止时,不再发起新的请求,所有新的调用在客户端即报错。然后检测是否还有请求的响应没返回,等待返回,如果超时则强制关闭。

二、如何解析dubbo的bean

代码语言:javascript
复制
<dubbo:service interface="com.ywl.test.TestApi"
               ref="testApi" retries="0" cluster="failfast" timeout="3000"/>

如上图所示,service、interface这些schema都是dubbo扩展的自定义解析配置,因此需要引入指定的dubbo自定义的schema。

代码语言:javascript
复制
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd

并且每个schema都有自己的解析类,dubbo标签对应的解析类,可以查看DubboNamespaceHandler类。

代码语言:javascript
复制
public void init() {
    registerBeanDefinitionParser("application",         new DubboBeanDefinitionParser(ApplicationConfig.class, true));
    registerBeanDefinitionParser("module",         new DubboBeanDefinitionParser(ModuleConfig.class, true));
    registerBeanDefinitionParser("registry",         new DubboBeanDefinitionParser(RegistryConfig.class, true));
    registerBeanDefinitionParser("monitor",         new DubboBeanDefinitionParser(MonitorConfig.class, true));
    registerBeanDefinitionParser("provider",         new DubboBeanDefinitionParser(ProviderConfig.class, true));
    registerBeanDefinitionParser("consumer",         new DubboBeanDefinitionParser(ConsumerConfig.class, true));
    registerBeanDefinitionParser("protocol",         new DubboBeanDefinitionParser(ProtocolConfig.class, true));
    registerBeanDefinitionParser("service",         new DubboBeanDefinitionParser(ServiceBean.class, true));
    registerBeanDefinitionParser("reference",         new DubboBeanDefinitionParser(ReferenceBean.class, false));
    registerBeanDefinitionParser("annotation",         new AnnotationBeanDefinitionParser());}

如上图所示,dubbo:service对应的为DubboBeanDefinitionParser解析器。

· DubboBeanDefinitionParser

DubboBeanDefinitionParser会解析ref、service、timeout、version等元素,解析成spring的beanDefinition对象,注册到spring中。核心代码如下:

代码语言:javascript
复制
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
    RootBeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClass(beanClass);
    beanDefinition.setLazyInit(false);
    String id = element.getAttribute("id");
代码语言:javascript
复制
    //...
代码语言:javascript
复制
    if (id != null && id.length() > 0) {
        if (parserContext.getRegistry().containsBeanDefinition(id)) {
            throw new IllegalStateException("Duplicate spring bean id " + id);
        }        //注册到spring中
        parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
        beanDefinition.getPropertyValues().addPropertyValue("id", id);
    }    //...}

这里的注册其实就相当于往spring中的beanDefinitionMap中放入元素,key-dubbo配置的id,消费者为id,服务提供者为interface路径,value-配置的类解析成的beanDefinition对象。

三、总结

dubbo的使用其实也离不开spring容器的支持,dubbo与spring整合的核心在于DubboBeanDefinitionParser解析类。

下一篇会写下dubbo的服务发布原理。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码云大作战 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档