使用dubbo的人都会发现,它本身并没有内置什么启动容器,因为它启动的时候是通过特定的container实现,dubbo中有个模块就是管理各个容器的:
核心接口是 两个方法一个是启动,一个是停止
@SPI("spring") public interface Container { /** * start. */ void start(); /** * stop. */ void stop(); }
dubbo提供了三种容器管理的实现,分别是log4j,logback,spring
第一种是log4j的容器:Log4jContainer
package com.alibaba.dubbo.container.log4j; import com.alibaba.dubbo.common.utils.ConfigUtils; import com.alibaba.dubbo.container.Container; import org.apache.log4j.Appender; import org.apache.log4j.FileAppender; import org.apache.log4j.LogManager; import org.apache.log4j.PropertyConfigurator; import java.util.Enumeration; import java.util.Properties; /** * Log4jContainer. (SPI, Singleton, ThreadSafe) */ public class Log4jContainer implements Container { public static final String LOG4J_FILE = "dubbo.log4j.file"; public static final String LOG4J_LEVEL = "dubbo.log4j.level"; public static final String LOG4J_SUBDIRECTORY = "dubbo.log4j.subdirectory"; public static final String DEFAULT_LOG4J_LEVEL = "ERROR"; @SuppressWarnings("unchecked") public void start() { String file = ConfigUtils.getProperty(LOG4J_FILE); if (file != null && file.length() > 0) { String level = ConfigUtils.getProperty(LOG4J_LEVEL); if (level == null || level.length() == 0) { level = DEFAULT_LOG4J_LEVEL; } Properties properties = new Properties(); properties.setProperty("log4j.rootLogger", level + ",application"); properties.setProperty("log4j.appender.application", "org.apache.log4j.DailyRollingFileAppender"); properties.setProperty("log4j.appender.application.File", file); properties.setProperty("log4j.appender.application.Append", "true"); properties.setProperty("log4j.appender.application.DatePattern", "'.'yyyy-MM-dd"); properties.setProperty("log4j.appender.application.layout", "org.apache.log4j.PatternLayout"); properties.setProperty("log4j.appender.application.layout.ConversionPattern", "%d [%t] %-5p %C{6} (%F:%L) - %m%n"); PropertyConfigurator.configure(properties); } String subdirectory = ConfigUtils.getProperty(LOG4J_SUBDIRECTORY); if (subdirectory != null && subdirectory.length() > 0) { Enumerationls = LogManager.getCurrentLoggers(); while (ls.hasMoreElements()) { org.apache.log4j.Logger l = ls.nextElement(); if (l != null) { Enumeration as = l.getAllAppenders(); while (as.hasMoreElements()) { Appender a = as.nextElement(); if (a instanceof FileAppender) { FileAppender fa = (FileAppender) a; String f = fa.getFile(); if (f != null && f.length() > 0) { int i = f.replace('\\', '/').lastIndexOf('/'); String path; if (i == -1) { path = subdirectory; } else { path = f.substring(0, i); if (!path.endsWith(subdirectory)) { path = path + "/" + subdirectory; } f = f.substring(i + 1); } fa.setFile(path + "/" + f); fa.activateOptions(); } } } } } } } public void stop() { } }
第二种是基于logback:LogbackContainer
package com.alibaba.dubbo.container.logback; import com.alibaba.dubbo.common.utils.ConfigUtils; import com.alibaba.dubbo.common.utils.StringUtils; import com.alibaba.dubbo.container.Container; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.rolling.RollingFileAppender; import ch.qos.logback.core.rolling.TimeBasedRollingPolicy; import org.slf4j.LoggerFactory; /** * LogbackContainer. (SPI, Singleton, ThreadSafe) */ public class LogbackContainer implements Container { public static final String LOGBACK_FILE = "dubbo.logback.file"; public static final String LOGBACK_LEVEL = "dubbo.logback.level"; public static final String LOGBACK_MAX_HISTORY = "dubbo.logback.maxhistory"; public static final String DEFAULT_LOGBACK_LEVEL = "ERROR"; public void start() { String file = ConfigUtils.getProperty(LOGBACK_FILE); if (file != null && file.length() > 0) { String level = ConfigUtils.getProperty(LOGBACK_LEVEL); if (level == null || level.length() == 0) { level = DEFAULT_LOGBACK_LEVEL; } // maxHistory=0 Infinite history int maxHistory = StringUtils.parseInteger(ConfigUtils.getProperty(LOGBACK_MAX_HISTORY)); doInitializer(file, level, maxHistory); } } public void stop() { } /** * Initializer logback * * @param file * @param level * @param maxHistory */ private void doInitializer(String file, String level, int maxHistory) { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME); rootLogger.detachAndStopAllAppenders(); // appender RollingFileAppenderfileAppender = new RollingFileAppender (); fileAppender.setContext(loggerContext); fileAppender.setName("application"); fileAppender.setFile(file); fileAppender.setAppend(true); // policy TimeBasedRollingPolicy policy = new TimeBasedRollingPolicy (); policy.setContext(loggerContext); policy.setMaxHistory(maxHistory); policy.setFileNamePattern(file + ".%d{yyyy-MM-dd}"); policy.setParent(fileAppender); policy.start(); fileAppender.setRollingPolicy(policy); // encoder PatternLayoutEncoder encoder = new PatternLayoutEncoder(); encoder.setContext(loggerContext); encoder.setPattern("%date [%thread] %-5level %logger (%file:%line\\) - %msg%n"); encoder.start(); fileAppender.setEncoder(encoder); fileAppender.start(); rootLogger.addAppender(fileAppender); rootLogger.setLevel(Level.toLevel(level)); rootLogger.setAdditive(false); } }
第三种是基于spring,这个很重要的:SpringContainer
package com.alibaba.dubbo.container.spring; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ConfigUtils; import com.alibaba.dubbo.container.Container; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * SpringContainer. (SPI, Singleton, ThreadSafe) */ public class SpringContainer implements Container { public static final String SPRING_CONFIG = "dubbo.spring.config"; public static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml"; private static final Logger logger = LoggerFactory.getLogger(SpringContainer.class); static ClassPathXmlApplicationContext context; public static ClassPathXmlApplicationContext getContext() { return context; } public void start() { String configPath = ConfigUtils.getProperty(SPRING_CONFIG); if (configPath == null || configPath.length() == 0) { configPath = DEFAULT_SPRING_CONFIG; } //加载所有spring下面的配置文件,这里也包含了dubbo相关的配置文件 context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+")); context.start(); } public void stop() { try { if (context != null) { context.stop(); context.close(); context = null; } } catch (Throwable e) { logger.error(e.getMessage(), e); } } }
然后紧急着还有一个主方法来加在这些容器:Main
package com.alibaba.dubbo.container; import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.ConfigUtils; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; /** * Main. (API, Static, ThreadSafe) */ 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 ExtensionLoaderloader = 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) { String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName()); args = Constants.COMMA_SPLIT_PATTERN.split(config); } final List containers = new ArrayList() ; 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); } try { LOCK.lock(); STOP.signal(); } finally { LOCK.unlock(); } } } }); } 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); } try { LOCK.lock(); STOP.await(); } catch (InterruptedException e) { logger.warn("Dubbo service server stopped, interrupted by other thread!", e); } finally { LOCK.unlock(); } } }