dubbo 自产自销实践
项目中使用了dubbo做服务,由于既要作为消费者消费其他工程的服务,也要作为提供者对外提供服务,所以需要同时实现消费者和提供者。
基于SpringMVC 实现自产自销,实现过程如下:
1. servlet-mvc.xml 配置(片段)
这里主要看扫描 controller 所在的包
<!-- 使用Annotation自动注册Bean,只扫描@Controller -->
<context:component-scan base-package="com.xxx.prod.controller"
use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Service" />
</context:component-scan>
2. spring-context.xml 配置(片段),
这里主要看 Spring扫描Service实现类:
<!-- 使用Annotation自动注册Bean,解决事物失效问题:在主容器中不扫描@Controller注解,在SpringMvc中只扫描@Controller注解。 -->
<context:component-scan base-package="com.glorystone.prod.service"><!-- base-package 如果多个,用“,”分隔 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<!-- 导入生产者、消费者配置-->
<import resource="classpath*:spring-dubbo-provider.xml"/>
<import resource="classpath*:spring-dubbo-consumer.xml"/>
3. 提供者 spring-dubbo-provider.xml 配置:
这里需要注意的是,xmlns 和xsd 文件引入:
<?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:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--定义了提供方应用信息,用于计算依赖关系;在 dubbo-admin 或 dubbo-monitor 会显示这个名字,方便辨识-->
<dubbo:application name="product-provider"/>
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry protocol="zookeeper" address="${zookeeper.host}" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20881" />
<!-- 监控中心配置,protocol="registry",表示从注册中心发现监控中心地址 -->
<dubbo:monitor protocol="registry"/>
<!-- 当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值 -->
<dubbo:provider timeout="30000" threadpool="fixed" threads="100" accepts="1000" />
<!-- 注解实现扫描dubbo @Service 标记的类 -->
<dubbo:annotation package="com.glorystone.prod.provider" />
</beans>
这里使用zookeeper 协议来实现dubbo服务,注解方式实现。
接口模块的provider 包下写Service 如:
public interface HelloService {
String sayHi(String name);
}
实现模块实现HelloService:
import com.alibaba.dubbo.config.annotation.Service;
/**
* Created by wangwei on 2017/8/29.
*/
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHi(String name) {
return "hello, rose like " + name;
}
}
这里要注意的是, @Service 包是dubbo下的,不要使用Spring的@Service
4. 消费者 spring-dubbo-consumer.xml 配置
<dubbo:application name="product-consumer" default="false" />
<!--向 zookeeper 订阅 provider 的地址,由 zookeeper 定时推送-->
<dubbo:registry protocol="zookeeper" address="${zookeeper.host}"/>
<!--使用 dubbo 协议调用定义好的 接口-->
<!-- 注解方式 扫描consumer下 @Reference 的接口引用 -->
<dubbo:annotation package="com.glorystone.prod.consumer" />
这里需要注意下,受限 application 里配置了 * default=”false ” *, 因为如果不加这个,就会报
java.lang.IllegalStateException: Duplicate application configs: and
这个异常,意思是配置了两个 dubbo application , 加上这个就可以解决。
5. 消费者管理类
接着看consumer, 这个包下写了一个ConsumerManager 管理类:
package com.glorystone.prod.consumer;
import com.alibaba.dubbo.config.annotation.Reference;
import lombok.Getter;
import org.springframework.stereotype.Component;
/**
* Created by wangwei on 2017/8/30.
*/
@Component
public @Getter class ConsumerManager {
@Reference
private HelloService helloService ;
}
这里使用消费者,原本只需要在如controller 里 注入消费者service就行,但是这样的话,就需要配置消费者注解 扫描包到controller所在目录,这种情况下就会dubbo 和 spring 扫描包一样,导致冲突,使dubbo注解不生效。,因此需要写一层ConsumerManager 这个管理类,交给Spring管理,类里边写要引用的dubbo服务。
6. 使用dubbo服务
比如我们要在controller 里使用dubbo服务, 首先要把controller 所在模块 pom 加入 dubbo 服务接口的依赖,比如我的dubbo服务接口在prod-api模块, 我在我的controller模块就添加prod-api的依赖。
<dependency>
<groupId>com.xxx.prod</groupId>
<artifactId>prod-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
我在控制类里使用:
@Autowired
private ConsumerManager consumerManager;
@RequestMapping("/hello")
public void hello() {
System.out.println("<-- start product hello-->");
System.out.println(consumerManager.getHelloService().sayHi("jack"));
}
7. 启动tomcat 测试:
启动tomcat,登录dubbo-admin 管理平台,看到服务已经显示,
在浏览器请求 /hello,日志打印:
<-- start product automobile-->
hello, rose like jack
结束。
要点总结:
1. spring 扫描包路径 和 dubbo注解扫描包路径,不管是消费者还是生产者要分开。
2. 注意在消费者配置文件上加上 default=false