dubbo中文文档
准备工作
1 安装zookeeper 注册中心(dubbo 推荐使用)
2 dubbo 管理控制台(不安装也行)
idea 测试代码
分为三块:
公共接口模块--主要是一些bean 和要暴露的接口
服务提供者模块
服务消费者模块
--------------------------------------------------------------------------------------------------------------------
(1)首先服务提供者和服务消费者都需要依赖公共接口模块
在消费者和提供者的pom文件添加接口依赖
(2)在服务提供者和服务消费者pom文件中添加dubbo 和zookeeper依赖
1、引入dubbo
<!-- 引入dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!-- 由于我们使用zookeeper作为注册中心,所以需要操作zookeeper:
dubbo 2.6以前的版本引入zkclient操作zookeeper
dubbo 2.6及以后的版本引入curator操作zookeeper
下面两个zk客户端根据dubbo版本2选1即可
-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!-- curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
(3)然后开始配置服务提供者xml
1>配置应用名称
2>配置注册中心
3>配置要暴露的服务接口
4> 配置普通bean的接口实现
5>配置dubbo的socket通信
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--1-->
<dubbo:application name="web_provider" organization="com.ecpss" owner="a"></dubbo:application>
<!--2-->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
<!--3-->
<dubbo:service interface="com.ecpss.service.HelloService" ref="service"></dubbo:service>
<bean id="service" class="com.ecpss.impl.ServiceImpl"></bean>
<!--4-->
<dubbo:service interface="com.ecpss.service.UserService" ref="users"></dubbo:service>
<bean id="users" class="com.ecpss.impl.UserServiceImpl"></bean>
<!--5-->
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
</beans>
(4)配置消费者xml
1>配置应用名称
2>配置注册中心
3>配置接口的引用
<?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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="com.ecpss"></context:component-scan>
<!--1-->
<dubbo:application name="web_consumer" organization="com.ecpss" owner="a"></dubbo:application>
<!--2-->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
<!--3-->
<dubbo:reference id="demo" interface="com.ecpss.service.HelloService"></dubbo:reference>
<dubbo:reference interface="com.ecpss.service.UserService" id="user"></dubbo:reference>
</beans>
dubbo测试结束 测试代码推送到github 链接 https://github.com/haobaxucan/dubbo01.git
源码分析
从 https://github.com/alibaba/dubbo 拉取dubbo源码
Person.class.newInstance().aa();//使用类反射创建对象调用方法aa()
dubbo原理:
Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑。
1.spring容器启动,加载资源文件的时候,解析标签,然后根据名称空间找到对应的handler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
NamespaceHandlerResolver中的 resolve()方法进行解析,它的默认实现DefaultNamespaceHandlerResolver:
getHandlerMappings()方法会加载classpath下所有的"META-INF/spring.handlers"文件,并存放在handlerMappings(Map)中,在后续的解析xml自定义属性时会根据命名空间在handlerMappings中查找NamespaceHandler去解析:
这个和注意是所有的hanlder
public NamespaceHandler resolve(String namespaceUri) {
//获取所有已经配置的handler映射
Map<String, Object> handlerMappings = getHandlerMappings();
//根据命名空间找到对应的处理器对象或者Class
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
//是否是NamespaceHandler对象实例,所有的自定义命名空间处理器必须实现NamespaceHandler接口
//以前已经生成处理器对象,直接返回缓存的处理器对象
return (NamespaceHandler) handlerOrClassName;
}
else {
//没有做过解析,则返回的是类路径
String className = (String) handlerOrClassName;
try {
//根据类路径加载处理器Class
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
//生成处理器对象
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
//以命名空间uri为key值,理器对象为value值,保存到一个map中
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
}
代码主要通过调用getHandlerMappings()方法获得NamespaceHandler对象与命名空间URI的映射表,并从这个映射表中取出对象,判断是否已经生成了NamespaceHandler对象。若已生成NamespaceHandler对象,则立即返回该对象,否则生成NamespaceHandler对象,并把它存放到刚才的映射表中,这样下次再获取就不用再生成对象了。那何时建立NamespaceHandler对象与命名空间URI的映射呢?我们继续跟踪getHandlerMappings()方法
private Map<String, Object> getHandlerMappings() {
if (this.handlerMappings == null) {
synchronized (this) {
if (this.handlerMappings == null) {
try {
//handlerMappingsLocation默认为"META-INF/spring.handlers"
Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}
Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
// 把Properties对象中的key-value复制到handlerMappings中
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return this.handlerMappings;
}
使用PropertiesLoaderUtils.loadAllProperties()从handlerMappingsLocation指定的handlers文件加载命名空间名称和具体NamespaceHandler之间的关联配置。handlerMappingsLocation默认的路径是jar包下的META-INF目录下的spring.handlers文件.
由此,当解析到http://www.springframework.org/schema/context命名空间时,PropertiesLoaderUtils.loadAllProperties()就会将以http://www.springframework.org/schema/context为key,org.springframework.context.config.ContextNamespaceHandler处理器类的全限定名作为value存进handlerMappings这个Map中。当第一次调用DefaultNamespaceHandlerResolver类,的resolve(String namespaceUri)方法获取到处理器类的全限定名,再根据处理器类的全限定名生成处理器对象,并把该对象保存进handlerMappings中,这样下一次再获取就不会生成对象了。这样就完成了命名空间处理器注册了。
spring.bean包中springhanler 文件
这些自定义的NamespaceHandler都必须实现NamespaceHandler接口或继承NamespaceHandlerSupport.
如自定义的标签Dubbo比如:
以前是阿里巴巴的内部rpc框架,现在交给了apache托管
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
public DubboNamespaceHandler() {
}
public void init() {
this.registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
this.registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
this.registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
this.registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
this.registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
this.registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
this.registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
this.registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
this.registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
this.registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
每一个标签都有相应的xxxconfig,比如application就会有applicationConfig
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}//调用相应的解析器将标签放在集合中
而每一种标签的解析都会有对应标签解析器如dubbo的DubboBeanDefinitionParser,下面就是开始dubbo 标签的解析。
dubbo每一种标签都有对应的配置,AbstractConfig是所有其它配置的父类,主要是一些标签的配置解析
ServiceConfig 服务提供者的配置 添加参数配置信息,且暴露服务
ReferenceConfig 服务消费者的配置 添加参数配置信息,且引用服务
----------------------------------------------------------------------------------------------------
运行dubbo服务
1.直接运行tomcat--浪费资源
2.自建main 加载spring配置文件---测试可用
3.使用dubbo 框架提供的Main方法---建议使用
优雅关机:不接受请求,如果线程池还有业务在运行,只等待业务执行完成
消费端
1.打成war
2.如果是被依赖的模块需要构建(如--构建到本地)
3.环境变量
4.安装tomcat