入口模块
dubbo-container-api-
入口方法解析
com.alibaba.dubbo.container.Main入口类Main设计得并不复杂,主要干了三件事情:
- 通过SPI加载具体的容器实例
- 注册JVM关闭钩子,实现优雅停机
- 服务启动与阻塞
加载dubbo容器实例代码:
public class Main {
public static final String CONTAINER_KEY = "dubbo.container";
private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);
// 省略...
public static void main(String[] args) {
try {
if (args == null || args.length == 0) {
// 检查配置文件中有没有指定dubbo.container,如果没有的话,加载默认的配置,并获取默认配置参数
String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName());
args = Constants.COMMA_SPLIT_PATTERN.split(config);
}
// 获取@SPI注解标注的Container实例,后面启动时一一加载
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.");
}
// 省略...
SPI机制后续解析......
服务启动:
public class Main {
// ...
// 获取对象级别的锁
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Condition STOP = LOCK.newCondition();
public static void main(String[] args) {
try {
// ...
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);
// 发生异常,触发JVM钩子操作
System.exit(1);
}
try {
// 获取对象锁
LOCK.lock();
// 相当于wait()操作,挂起主线程
STOP.await();
} catch (InterruptedException e) {
logger.warn("Dubbo service server stopped, interrupted by other thread!", e);
} finally {
// 释放对象锁
LOCK.unlock();
}
}
注册ShutdownHook:
public class Main {
public static final String SHUTDOWN_HOOK_KEY = "dubbo.shutdown.hook";
// ...
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Condition STOP = LOCK.newCondition();
public static void main(String[] args) {
// dubbo.shutdown.hook配置为true才会进行注册
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 {
container.stop(); // 执行容器关闭操作
logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!");
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
try {
// 获取对象锁
LOCK.lock();
// signal()相当于notifyAll(),唤醒所有处于wait状态的线程
// 这些线程自动竞争与释放对象锁,直至所有线程执行完毕
STOP.signal();
} finally {
// 释放对象锁
LOCK.unlock();
}
}
}
});
}
// ...
}
整体来讲,dubbo封装完善,因此启动类非常简单,但是深入细节,里面有许多深入细致的操作,需要仔细钻研
下期看看dubbo的SPI机制