文章目录
1. 创建聚合项目
创建一个聚合项目demo-dubbo,其结构如下
demo-dubbo (pom)
|-- dubbo-api (pom)
|-- dubbo-client (war)
|-- dubbo-provider (war)
-
api:对外接口,结构简单,没有业务逻辑,该模块内定义的有服务接口、服务模型、服务异常。
-
provider:接口实现,实现api接口的具体业务逻辑,需要引入api的pom。
-
client:消费方,不关系provider具体实现,单单引入api的pom即可。
demo-dubbo
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo.dubbo</groupId>
<artifactId>demo-dubbo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>dubbo-server</module>
<module>dubbo-client</module>
<module>dubbo-api</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.8</jdk.version>
<!-- 单元测试 -->
<junit.version>4.12</junit.version>
<!-- 日志 -->
<log4j.version>1.2.17</log4j.version>
<logback.version>1.2.2</logback.version>
<slf4j.version>1.7.25</slf4j.version>
<!-- lombok -->
<lombok.version>1.18.0</lombok.version>
<!-- dubbo -->
<dubbo.version>2.7.2</dubbo.version>
<!-- zookeeper -->
<zk.version>3.4.9</zk.version>
<zk.client.version>0.2</zk.client.version>
<!-- spring -->
<spring.version>4.3.2.RELEASE</spring.version>
<curator.version>2.12.0</curator.version>
</properties>
<dependencies>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- zk -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zk.version}</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>${zk.client.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
<exclusions>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument-tomcat</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>
<profile>
<id>local</id>
<properties>
<profile.env>local</profile.env>
</properties>
<build>
<resources>
<resource>
<directory>src/main/profiles/local</directory>
</resource>
</resources>
</build>
</profile>
</profiles>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/profiles/${profile.env}</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.2</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</build>
</project>
dubbo-client
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo-dubbo</artifactId>
<groupId>com.demo.dubbo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-client</artifactId>
<packaging>war</packaging>
<name>dubbo-client Maven Webapp</name>
<dependencies>
<!-- api -->
<dependency>
<groupId>com.demo.dubbo</groupId>
<artifactId>dubbo-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- zk -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<exclusions>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
</dependency>
</dependencies>
<build>
<finalName>dubbo-client</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/profiles/${profile.env}</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<encoding>UTF-8</encoding>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>pem</nonFilteredFileExtension>
<nonFilteredFileExtension>pfx</nonFilteredFileExtension>
<nonFilteredFileExtension>p12</nonFilteredFileExtension>
<nonFilteredFileExtension>crt</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
</build>
</project>
dubbo-provider
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo-dubbo</artifactId>
<groupId>com.demo.dubbo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-server</artifactId>
<packaging>war</packaging>
<name>dubbo-server Maven Webapp</name>
<properties>
<mysql.version>5.1.5</mysql.version>
<druid.version>1.1.9</druid.version>
</properties>
<dependencies>
<!-- api -->
<dependency>
<groupId>com.demo.dubbo</groupId>
<artifactId>dubbo-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- datasource -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- zk -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<exclusions>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
</dependency>
</dependencies>
<build>
<finalName>dubbo-server</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/profiles/${profile.env}</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<encoding>UTF-8</encoding>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>pem</nonFilteredFileExtension>
<nonFilteredFileExtension>pfx</nonFilteredFileExtension>
<nonFilteredFileExtension>p12</nonFilteredFileExtension>
<nonFilteredFileExtension>crt</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 代码编写
接口创建
在api模块中创建DemoRpcService
public interface DemoRpcService {
/**
* say something
* @param msg
*/
void say(String msg);
}
provider
在provider模块中创建实现类DemoRpcServiceImpl
@Slf4j
public class DemoRpcServiceImpl implements DemoRpcService {
@Override
public void say(String msg) {
log.info("你让我说:{}", msg);
}
}
配置生产信息spring-provider.xml
<?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: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">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="demo-provider" />
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 服务接口实现 -->
<bean id="demoRpcService" class="com.bye.server.rpc.service.impl.DemoRpcServiceImpl" />
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.bye.server.rpc.service.DemoRpcService" ref="demoRpcService"/>
</beans>
comsumer
在client模块中创建消费类DubboRpcTest
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-application.xml"})
//application.xml中引入了spring-consumer.xml
public class DubboRpcTest {
@Resource
private DemoRpcService demoRpcService;
/**
* 一个普通的dubbo接口
*/
@Test
public void dubboTest() {
demoRpcService.say("Hello");
}
}
配置消费信息spring-consumer.xml
<?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: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">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="demo-consumer" />
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="demoRpcService" interface="com.bye.server.rpc.service.DemoRpcService" />
</beans>
启动测试
首先,先启动provider。
启动类如下DemoXmlProviderBootStrap
:
@Slf4j
public class DemoXmlProviderBootStrap {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-provider.xml");
context.start();
log.info("dubbo service started.");
// 按任意键退出
System.in.read();
}
}
启动日志如下:
[2019-07-08 10:39:14 144][main-EventThread][ConnectionStateManager:228][]State change: CONNECTED
[2019-07-08 10:39:15 025][main][DemoXmlProviderBootStrap:17][]dubbo service started.
接着执行DubboRpcTest.dubboTest
,provider执行日志如下:
[2019-07-08 10:40:22 455][DubboServerHandler-10.0.54.184:20880-thread-2][DemoRpcServiceImpl:22][]你让我说:Hello
3. 实战-隐式传参+过滤器
我的项目中,使用到了mdc日志跟踪。如果跨服务调用,则每个服务中会有自己的mdc线程, 如何让消费方mdc线程的id无痕迹的传递给生产者呢?
首先,代码零入侵,可以使用过滤器。
其次,开发无感知,可以使用隐式传参。
具体实现如下:
MDC
MDC工具如下:
@Slf4j
public final class MDCUtil {
public static final String LOG_ID = "LOGID";
/**
* 创建日志线程号
*/
public static void put() {
MDC.put(LOG_ID, uuid());
}
/**
* 创建日志线程号
*
* @param logId
*/
public static void put(String logId) {
if (logId == null || "".equals(logId)) {
logId = uuid();
log.warn("logId is empty, set a default value:{}", logId);
}
MDC.put(LOG_ID, logId);
}
/**
* 获取日志线程号
*
* @return
*/
public static String get() {
return MDC.get(LOG_ID);
}
private static String uuid() {
return UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
}
}
logback.xml
logback.xml配置如下
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- [2017-12-19 15:20:58 278][thread-0][Demo_log.main 19][uuid] -->
<pattern>[%d{yyyy-MM-dd HH:mm:ss SSS}][%t][%c{0}:%L][%X{LOGID}]%msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console" />
</root>
</configuration>
生产者过滤器
创建TraceProviderFilter
public class TraceProviderFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//从隐式传参中获取logid
String logId = RpcContext.getContext().getAttachment(MDCUtil.LOG_ID);
MDCUtil.put(logId);
return invoker.invoke(invocation);
}
}
扩展过滤器,在provider模块resources下,创建META-INF/dubbo
。创建一个文件org.apache.dubbo.rpc.Filter
。配置如下:
traceProviderFilter=com.bye.server.rpc.filter.TraceProviderFilter
在spring-provider.xml
中配置全局过滤器
<!-- mdc过滤器 -->
<dubbo:provider filter="traceProviderFilter" />
最后,启动生产者。
消费者过滤器
创建TraceConsumerFilter
@Slf4j
public class TraceConsumerFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String logId = MDCUtil.get();
RpcContext.getContext().setAttachment(MDCUtil.LOG_ID, logId);
return invoker.invoke(invocation);
}
}
扩展过滤器,在client模块resources下,创建META-INF/dubbo
。创建一个文件org.apache.dubbo.rpc.Filter
。配置如下:
traceConsumerFilter=com.bye.client.rpc.filter.TraceConsumerFilter
在spring-consumer.xml
中配置全局过滤器
<!-- mdc过滤器 -->
<dubbo:provider filter="traceConsumerFilter" />
编写测试类
在client模块,DubboRpcTest
增加一个@before
@Before
public void before() {
MDCUtil.put();
}
在dubboTest()
方法中增加一句日志输出,执行。
@Test
public void dubboTest() {
log.info("我是消费者");
demoRpcService.say("Hello");
}
日志查看
消费方输出日志
[2019-07-08 12:46:15 189][main][DubboRpcTest:37][babc11b0d28a4133aec905e9b5480eef]我是消费者
生产者输出日志
[2019-07-08 12:46:15 396][DubboServerHandler-10.0.54.184:20880-thread-2][DemoRpcServiceImpl:22][babc11b0d28a4133aec905e9b5480eef]你让我说:Hello
MDC线程ID一致。
4. 实战-异步调用
在日常开发中,我们会遇到这种情况,调用了一个服务A,但是并不关心服务A执行成功与否,或者不关心服务A的返回结果,或者服务A执行有段时间,但不要长时间阻塞消费者。这个时候就可以使用到异步调用。
异步调用是dubboV2.7中三大特性之一,按照从生产者和消费者的角度可以分为
消费者 | 生产者 |
---|---|
同步 | 同步 |
同步 | 异步 |
异步 | 同步 |
异步 | 异步 |
同步-同步为我们最常用的。消费者异步我也没有遇到过这种场景,比较少。同步-异步,这个还是有应用场景的。
同步-异步,不等待生产者结果
在api模块,DemoRpcService
中定义异步接口
CompletableFuture<Void> asyncSay2(String msg);
在provider模块,DemoRpcServiceImpl
中实现asyncSay2
方法
@Override
public CompletableFuture<Void> asyncSay2(String msg) {
String logId = MDCUtil.get();
// 建议为supplyAsync提供自定义线程池,避免使用JDK公用线程池
return CompletableFuture.supplyAsync(() -> {
MDCUtil.put(logId);
log.info("你让我说:{}", msg);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("provider run time 3 seconds and response");
return null;
});
}
异步-异步,消费者调用生产者后,先处理自己逻辑,在等待生产者结果返回
在api模块,DemoRpcService
中定义异步接口
CompletableFuture<String> asyncSay(String msg);
在provider模块,DemoRpcServiceImpl
中实现asyncSay2
方法
@Override
public CompletableFuture<String> asyncSay(String msg) {
String logId = MDCUtil.get();
// 建议为supplyAsync提供自定义线程池,避免使用JDK公用线程池
return CompletableFuture.supplyAsync(() -> {
MDCUtil.put(logId);
log.info("你让我说:{}", msg);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("provider run time 3 seconds and response");
return "async response from provider.";
});
}
生产者配置
在spring-provider.xml
中配置如下
<!-- 服务接口实现 -->
<bean id="demoRpcService" class="com.bye.server.rpc.service.impl.DemoRpcServiceImpl" />
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.bye.server.rpc.service.DemoRpcService" ref="demoRpcService">
<!-- sent="true" 等待消息发出,消息发送失败将抛出异常。
sent="false" 不等待消息发出,将消息放入 IO 队列,即刻返回。-->
<dubbo:method name="asyncSay" timeout="10000" />
<!-- 完全忽略返回值,可以配置 return="false",以减少 Future 对象的创建和管理成本: -->
<dubbo:method name="asyncSay2" timeout="10000" return="false" />
</dubbo:service>
消费者测试
/**
* 异步调用-不等待服务器响应结果
*/
@Test
public void asyncSay2() {
log.info("call start");
demoRpcService.asyncSay("Hello");
log.info("say something");
}
/**
* 异步调用-调用后,先处理自己逻辑,在等待服务器响应结果
*/
@Test
public void asyncSay() {
log.info("call start");
CompletableFuture<String> future = demoRpcService.asyncSay("Hello");
future.whenComplete((v, t) -> {
if (t != null) {
t.printStackTrace();
} else {
log.info("call end, provider response msg:{}", v);
}
});
log.info("say something");
}