dubbo源码深度解读三之container模块

来源:互联网 发布:手机音乐可视化软件 编辑:程序博客网 时间:2024/06/07 12:56

前言:container为服务容器,用于部署运行服务,是一个Standlone的容器,以简单的Main加载Spring启动,因为服务通常不需要Tomcat/JBoss等Web容器的特性,没必要用Web容器去加载服务。

一,Container接口
这是一个基类的接口,这这个模块中,他的实现类有SpringContainer、Log4jContainer、JettyContainer、LogbackContainer。
看下源码:

@SPI("spring")public interface Container {    /**     * start.     */    void start();    /**     * stop.     */    void stop();}

可以发现,它有一个SPI注解,这个在common模块中已经说明了,接下来看它模块中三个实现类

二,Spring Container
主要指定了默认的配置文件路径(自动加载META-INF/spring目录下的所有Spring配置),通过ClassPathXmlApplicationContext来启动spring容器。
由于实现了Container接口,那么在resources下面找到com.alibaba.dubbo.container.Container文件中,可以看到spring=com.alibaba.dubbo.container.spring.SpringContainer,这是SPI扩展的相关知识。

三,Jetty Container
启动一个内嵌Jetty,用于汇报状态,但是在大量访问页面时,会影响服务器的线程和内存
配置:(配在java命令-D参数或者dubbo.properties中)

 dubbo.jetty.port=8080 ----配置jetty启动端口  dubbo.jetty.directory=/foo/bar ----配置可通过jetty直接访问的目录,用于存放静态文件  dubbo.jetty.page=log,status,system ----配置显示的页面,缺省加载所有页面

四,Log4j Container
自动配置log4j的配置,在多进程启动时,自动给日志文件按进程分目录。

五,容器的启动
我们先来看Main类的main函数

public static void main(String[] args) {        try {            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 ++) {                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);                            }                            synchronized (Main.class) {                                running = false;                                Main.class.notify();                            }                        }                    }                });            }            //根据参数启动容器            for (Container container : containers) {                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);        }        synchronized (Main.class) {            while (running) {                try {                    Main.class.wait();                } catch (Throwable e) {                }            }        }    }

所以我们在启动容器时候,可以选择spring、jetty、log4j、logback等参数。

六,容器的停机
Dubbo是通过JDK的ShutdownHook来完成优雅停机的,所以如果用户使用”kill -9 PID”等强制关闭指令,是不会执行优雅停机的,只有通过”kill PID”时,才会执行。
此时有下面的情况
1,服务提供方
停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。
然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。

2,服务消费方
停止时,不再发起新的调用请求,所有新的调用在客户端即报错。
然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。

原创粉丝点击