dubbo中的角色
Container 容器
Provider 生成者
Consumer 消费者
Registry 注册中心
Monitor 监控中心
dubbo的流程
首先,加载dubbo容器,这里我们来看下源码dubbo都加载了哪些容器:
这里我们使用的是dubbo的main方法启动dubbo,首先找到dubbo的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);
private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);
private static volatile boolean running = true;
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) {
}
}
}
}
}
看下这个源码中有一个关键的部分:启动容器,然后我们到container
Container是一个接口,在idea下使用ctrl+Alt+B快捷键看下,该接口的实现类:
这四个便是dubbo的全部容器,但是这四个容器并不会全部加载,如果在启动dubbo时不传参数的话,默认是只会加载Spring容器的,这里可以自行debugger一下,我这里也演示下:
首先会进入这个判断:
然后这里反射调用到了SpringContainer并将它添加到了containers中
然后再到这,启动容器:
启动SpirngContainer时会去加载Spring的配置文件,这里我们再看下源码:
如果传入了启动容器的参数则会加载传入的容器名的容器,这里有个前提,你的maven库中得有这个容器的jar包,比如我的maven库没有jetty的jar包我这里加入jetty容器就报错了:
然后生产者注册服务,这里的注册中心可以是zookeeper,redis等,我们这里注册中心以zookeeper为例,注册服务时将服务url添加到了providers下
启动服务前:生产者为空
启动服务后:
可以看到,生产者将url信息以临时节点的方式注册到了zookeeper上
然后dubbo订阅服务,如果没有订阅到自己想获得的服务,它会不断的尝试订阅。新的服务注册到注册中心以后,注册中心会将这些服务通过notify到消费者(这里我觉着就是利用了zookeeper的watcher监听事件)。
Monitor是监控中心,Consumer 和Provider通过异步的方式发送消息至Monitor,Consumer和Provider会将信息存放在本地磁盘,平均1min会发送一次信息。Monitor在整个架构中是可选的,Monitor功能需要单独配置,不配置或者配置以后,Monitor挂掉并不会影响服务的调用。Monitor也是一个dubbo服务
registry的可视化war包(dubbo-admin)和Monitor的源码包都可以从dubbo官网下载,dubbo从2.6.0以后就没有dubbo-admin了,在使用时需要先修改配置文件中的注册中心地址为你的实际地址