一、Main方法是启动加载,spring默认配置,日志框架的加载
1、从Main的入口可以看见,加载时使用了钩子对配置或者默认配置的container进行加载(也就是dubbo-container源码中的四个模块,日志、spring容器、服务器(现在只能使用jetty)和logback),会加载子模块下的/dubbo-container/dubbo-container-spring/target/classes/META-INF/dubbo/internal/com.alibaba.dubbo.container.Container(四个container的位置一致)。
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.container;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
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;
/**
* Main. (API, Static, ThreadSafe)
*
* @author william.liangf
*/
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);
}
// dubbo的核心扩展机制(从dubbo的dubbo-contrainer源码部分可以看见包含jetty、log4j、logback、spring的容器)
final List<Container> containers = new ArrayList<Container>();
for (int i = 0; i < args.length; i ++) {
// 就会加载默认或者配置好的容器(spring也是从该处进行加载)
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) {
}
}
}
}
}
2、加载日志模块的container的时候会使用工厂进行初始化,也说明了可以在
<dubbo:application name="order-prodider" owner="kevin" logger="slf4j" />
中进行配置的logger属性的值,并且默认值为log4j。
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.common.logger;
import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.common.logger.jcl.JclLoggerAdapter;
import com.alibaba.dubbo.common.logger.jdk.JdkLoggerAdapter;
import com.alibaba.dubbo.common.logger.log4j.Log4jLoggerAdapter;
import com.alibaba.dubbo.common.logger.slf4j.Slf4jLoggerAdapter;
import com.alibaba.dubbo.common.logger.support.FailsafeLogger;
/**
* 日志输出器工厂
*
* @author william.liangf
*/
public class LoggerFactory {
private LoggerFactory() {
}
private static volatile LoggerAdapter LOGGER_ADAPTER;
private static final ConcurrentMap<String, FailsafeLogger> LOGGERS = new ConcurrentHashMap<String, FailsafeLogger>();
// 查找常用的日志框架
static {
String logger = System.getProperty("dubbo.application.logger");
if ("slf4j".equals(logger)) {
setLoggerAdapter(new Slf4jLoggerAdapter());
} else if ("jcl".equals(logger)) {
setLoggerAdapter(new JclLoggerAdapter());
} else if ("log4j".equals(logger)) {
setLoggerAdapter(new Log4jLoggerAdapter());
} else if ("jdk".equals(logger)) {
setLoggerAdapter(new JdkLoggerAdapter());
} else {
try {
setLoggerAdapter(new Log4jLoggerAdapter());
} catch (Throwable e1) {
try {
setLoggerAdapter(new Slf4jLoggerAdapter());
} catch (Throwable e2) {
try {
setLoggerAdapter(new JclLoggerAdapter());
} catch (Throwable e3) {
setLoggerAdapter(new JdkLoggerAdapter());
}
}
}
}
}
public static void setLoggerAdapter(String loggerAdapter) {
if (loggerAdapter != null && loggerAdapter.length() > 0) {
setLoggerAdapter(ExtensionLoader.getExtensionLoader(LoggerAdapter.class).getExtension(loggerAdapter));
}
}
/**
* 设置日志输出器供给器
*
* @param loggerAdapter
* 日志输出器供给器
*/
public static void setLoggerAdapter(LoggerAdapter loggerAdapter) {
if (loggerAdapter != null) {
Logger logger = loggerAdapter.getLogger(LoggerFactory.class.getName());
logger.info("using logger: " + loggerAdapter.getClass().getName());
LoggerFactory.LOGGER_ADAPTER = loggerAdapter;
for (Map.Entry<String, FailsafeLogger> entry : LOGGERS.entrySet()) {
entry.getValue().setLogger(LOGGER_ADAPTER.getLogger(entry.getKey()));
}
}
}
/**
* 获取日志输出器
*
* @param key
* 分类键
* @return 日志输出器, 后验条件: 不返回null.
*/
public static Logger getLogger(Class<?> key) {
FailsafeLogger logger = LOGGERS.get(key.getName());
if (logger == null) {
LOGGERS.putIfAbsent(key.getName(), new FailsafeLogger(LOGGER_ADAPTER.getLogger(key)));
logger = LOGGERS.get(key.getName());
}
return logger;
}
/**
* 获取日志输出器
*
* @param key
* 分类键
* @return 日志输出器, 后验条件: 不返回null.
*/
public static Logger getLogger(String key) {
FailsafeLogger logger = LOGGERS.get(key);
if (logger == null) {
LOGGERS.putIfAbsent(key, new FailsafeLogger(LOGGER_ADAPTER.getLogger(key)));
logger = LOGGERS.get(key);
}
return logger;
}
/**
* 动态设置输出日志级别
*
* @param level 日志级别
*/
public static void setLevel(Level level) {
LOGGER_ADAPTER.setLevel(level);
}
/**
* 获取日志级别
*
* @return 日志级别
*/
public static Level getLevel() {
return LOGGER_ADAPTER.getLevel();
}
/**
* 获取日志文件
*
* @return 日志文件
*/
public static File getFile() {
return LOGGER_ADAPTER.getFile();
}
}
3、加载spring的container的时,约定优于配置的"classpath*:META-INF/spring/*.xml"位置加载spring配置
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.container.spring;
import org.springframework.context.support.ClassPathXmlApplicationContext;
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 com.alibaba.dubbo.container.Container;
/**
* SpringContainer. (SPI, Singleton, ThreadSafe)
*
* @author william.liangf
*/
public class SpringContainer implements Container {
private static final Logger logger = LoggerFactory.getLogger(SpringContainer.class);
public static final String SPRING_CONFIG = "dubbo.spring.config";
// 所以默认加载classpath*:META-INF/spring/*.xml的spring配置
public static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml";
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;
}
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);
}
}
}
二、Admin控制中心(用来做服务的治理,如:服务的权重、服务的路由等)
在spring源码中找到dubbo-admin的web项目,将该服务进行启动,单独进行部署即可。
启动前在/dubbo-admin/src/main/webapp/WEB-INF/dubbo.properties中修改注册中心的地址和使用的用户信息,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>/WEB-INF/dubbo.properties</value>
<value>file://${user.home}/dubbo.properties</value>
</list>
</property>
</bean>
<dubbo:application name="dubbo-admin" />
<dubbo:registry address="${dubbo.registry.address}" check="false" file="false" />
<dubbo:reference id="registryService" interface="com.alibaba.dubbo.registry.RegistryService" check="false" />
<bean id="configService" class="com.alibaba.dubbo.governance.service.impl.ConfigServiceImpl" />
<bean id="consumerService" class="com.alibaba.dubbo.governance.service.impl.ConsumerServiceImpl" />
<bean id="overrideService" class="com.alibaba.dubbo.governance.service.impl.OverrideServiceImpl" />
<bean id="ownerService" class="com.alibaba.dubbo.governance.service.impl.OwnerServiceImpl" />
<bean id="providerService" class="com.alibaba.dubbo.governance.service.impl.ProviderServiceImpl" ></bean>
<bean id="routeService" class="com.alibaba.dubbo.governance.service.impl.RouteServiceImpl" />
<bean id="userService" class="com.alibaba.dubbo.governance.service.impl.UserServiceImpl">
<property name="rootPassword" value="${dubbo.admin.root.password}" />
<property name="guestPassword" value="${dubbo.admin.guest.password}" />
</bean>
<bean id="governanceCache" class="com.alibaba.dubbo.governance.sync.RegistryServerSync" />
</beans>
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
三、Simple监控中心(监控服务的调用次数、调用关系、响应时间等)
监控中心本身就是一个dubbo服务,同样也会注册到注册中心。
同样在/dubbo-monitor-simple/src/main/assembly/conf/dubbo.properties中提供了以下配置:
##
# Copyright 1999-2011 Alibaba Group.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
dubbo.container=log4j,spring,registry,jetty
dubbo.application.name=simple-monitor
dubbo.application.owner=
dubbo.registry.address=multicast://224.5.6.7:1234
#dubbo.registry.address=zookeeper://127.0.0.1:2181
#dubbo.registry.address=redis://127.0.0.1:6379
#dubbo.registry.address=dubbo://127.0.0.1:9090
dubbo.protocol.port=7070
dubbo.jetty.port=8080
dubbo.jetty.directory=${user.home}/monitor
dubbo.charts.directory=${dubbo.jetty.directory}/charts
dubbo.statistics.directory=${user.home}/monitor/statistics
dubbo.log4j.file=logs/dubbo-monitor-simple.log
dubbo.log4j.level=WARN
四、Dubbo提供的telnet命令(进入后可以使用 ls pwd clear invoke 等命令)
1、telnet ip port 到服务提供的服务器
2、cd com.kevin.dubbo.order.IOrderServices 找服务的地址
3、使用invoke对服务进行调用