dubbo 实践
什么是 dubbo
根据官方文档的说法,dubbo是一款 RPC 服务开发框架。其用于微服务之间的服务治理和通信。
在实践中,除了用于微服务开发,也可以用于多个业务实例中某一业务过程的同步调用。
demo 示例
方便起见,创建一个 Spring Boot 项目,使用 Gradle 作为依赖管理和构建工具。
文件 settings.gradle
1 2 3 4
| rootProject.name = 'nacos-dubbo-test'
include 'api' include 'service'
|
文件 build.gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| plugins { id 'java' }
group 'top.kanchitsu' version '1.0-SNAPSHOT'
repositories { maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://maven.aliyun.com/repository/spring/' } mavenLocal() mavenCentral() }
dependencies { implementation 'org.springframework.boot:spring-boot-starter:2.7.18' implementation 'org.apache.dubbo:dubbo-spring-boot-starter:3.3.4' implementation 'org.apache.dubbo:dubbo-nacos-spring-boot-starter:3.3.4' implementation project(':api') }
test { useJUnitPlatform() } subprojects { apply plugin: 'java'
repositories { maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://maven.aliyun.com/repository/spring/' } mavenLocal() mavenCentral() }
}
|
创建 api
api 子项目中用于定义 RPC 接口
文件 build.gradle
1 2 3 4 5 6
| plugins { id 'java' }
group 'top.kanchitsu' version '1.0-SNAPSHOT'
|
文件 DemoService.java
1 2 3 4 5
| package top.kanchitsu.api;
public interface DemoService { String sayHello(String name); }
|
创建 api 的实现(provider)
service 子项目用于实现已定义的 RPC 接口
文件 build.gradle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| plugins { id 'java' }
group 'top.kanchitsu' version '1.0-SNAPSHOT'
dependencies { implementation 'org.springframework.boot:spring-boot-starter:2.7.18' implementation 'org.apache.dubbo:dubbo-spring-boot-starter:3.3.4' implementation 'org.apache.dubbo:dubbo-nacos-spring-boot-starter:3.3.4'
implementation project(':api') }
test { useJUnitPlatform() }
|
文件 DemoServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12
| package top.kanchitsu.service;
import org.apache.dubbo.config.annotation.DubboService; import top.kanchitsu.api.DemoService;
@DubboService public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { return "Hello " + name; } }
|
文件 application.yml
1 2 3 4 5 6 7 8
| dubbo: registry: address: nacos://${nacos.address:127.0.0.1}:8848?username=nacos&password=VOLtOugsgy register-mode: instance application: name: demo01-consumer logger: slf4j qos-port: 22223
|
使用 api(customer)
在根项目中使用api
文件Consumer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package top.kanchitsu.Consumer;
import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import top.kanchitsu.api.DemoService;
@Component public class Consumer implements CommandLineRunner { @DubboReference(scope = "remote") private DemoService demoService;
@Override public void run(String... args) throws Exception { String result = demoService.sayHello("world"); System.out.println("Receive result ======> " + result); } }
|
文件Main.java
1 2 3 4 5 6 7 8 9 10 11
| package top.kanchitsu;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class Main { public static void main(String[] args) { SpringApplication.run(Main.class); } }
|
文件 application.yml
1 2 3 4 5 6 7 8
| dubbo: registry: address: nacos://${nacos.address:127.0.0.1}:8848?username=nacos&password=VOLtOugsgy register-mode: instance application: name: demo01-consumer logger: slf4j qos-port: 22223
|
启动
使用 dubbo 的项目需要一个注册中心,注册中心提供服务注册、服务发现等功能。这里直接使用已构建好的 nacos 服务端作为注册中心
Windows:
*unix:
然后依次启动 provider、customer,观察输出,出现以下内容视为成功
在 AOP 中使用 dubbo
dubbo 支持泛化调用,允许在没有提供 API 定义的情况下调用目标服务,这为改造现有业务代码提供了极大的便利。
考虑以下需求,同一单体应用部署了多了实例在不同服务器上,其中部分业务过程在执行后需要在其他实例上执行一次以同步操作,并视需要统一提交或回滚事务操作。
在 AOP 中使用 dubbo 可大幅度降低对现有业务代码的侵入性。
创建一个注解@BusinessProcessSync
文件BusinsessProcessSync.java
1 2 3 4 5 6 7 8
| import java.lang.annotation.*;
@Target({ElementType.METHOD}) @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface BusinessProcessSync { }
|
创建 AOP 切面
文件BusinsessProcessSyncAspect.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @Aspect @Component public class BusinsessProcessSyncAspect { @Resource private ApplicationContext applicationContext;
@Resource private ServiceDiscovery serviceDiscovery; @Around(value="@annotation(BusinessProcessSync)") public Object around(ProceedingJobPoint pjp){
ReferenceConfig<GenericService> referenceConfig = new ReferenceConfig<>(); referenceConfig.setGeneric("true"); List<ServiceInstance> instances = serviceDiscovery.getInstances(serviceName) .stream() .filter(instance -> !isCurrentInstance(instance)) .collect(Collectors.toList()); ExecutorService executor = Executors.newCachedThreadPool(); for (ServiceInstance instance : instances) { executor.execute(() -> { try { Object serviceProxy = createServiceProxy(instance, serviceName); Method method = findMethod(serviceProxy.getClass(), methodName, params); method.invoke(serviceProxy, params); } catch (Exception e) { } }); } } }
|
按照此方案,dubbo 将在 AOP 中以泛化调用的形式,执行其他实例中相同的业务过程