开篇用一个最简单的例子,来介绍如何用Dubbo搭建一个简单的例子。
本例包括:
创建项目,并创建三个Module,项目结构如下:
项目结构
整体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>org.example</groupId> <artifactId>Study</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>consumer</module> <module>provider</module> <module>interface</module> </modules> <properties> <spring-boot.version>2.3.1.RELEASE</spring-boot.version> <dubbo.version>2.7.5</dubbo.version> </properties> <dependencyManagement> <dependencies> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Apache Dubbo --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-bom</artifactId> <version>${dubbo.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>${dubbo.version}</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </dependencyManagement></project>consumer的依赖为:
<?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>Study</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>consumer</artifactId> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.example</groupId> <artifactId>interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- Dubbo Spring Boot Starter --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.5</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Zookeeper dependencies --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-rpc-http</artifactId> <version>${dubbo.version}</version> </dependency> </dependencies></project>interface的依赖为:
<?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>Study</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>interface</artifactId> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build></project>provider的依赖为:
<?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>Study</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>provider</artifactId> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.example</groupId> <artifactId>interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- Dubbo Spring Boot Starter --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.5</version> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jaxrs</artifactId> <version>3.0.19.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> </dependency> <!-- Zookeeper dependencies --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-rpc-http</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-metadata-report-zookeeper</artifactId> <version>${dubbo.version}</version> </dependency> </dependencies></project>@Service注解暴露服务
实现类
package com.zyz.provider.service;import com.zyz.DemoService;import org.apache.dubbo.common.URL;import org.apache.dubbo.config.annotation.Service;import org.apache.dubbo.rpc.RpcContext;@Service(version = "default")public class DefaultDemoService implements DemoService { @Override public String sayHello(String name) { System.out.println("执行了服务" + name); URL url = RpcContext.getContext().getUrl(); return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问 }}启动类
package com.zyz;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class DubboProviderDemo { public static void main(String[] args) { SpringApplication.run(DubboProviderDemo.class,args); }}配置文件application.properties:
# Spring boot applicationspring.application.name=dubbo-provider-demoserver.port=8081# Base packages to scan Dubbo Component: @org.apache.dubbo.config.annotation.Servicedubbo.scan.base-packages=com.zyz.provider.servicedubbo.application.name=${spring.application.name}## Dubbo Registrydubbo.registry.address=zookeeper://127.0.0.1:2181# Dubbo Protocoldubbo.protocol.name=dubbodubbo.protocol.port=20880日志文件log4j.properties:
###set log levels###log4j.rootLogger=info, stdout###output to the console###log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target=System.outlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n接口类DemoService:
package com.zyz;public interface DemoService { String sayHello(String name);}@Reference引入服务,加入版本表示具体引入哪一个实现类的实例
启动类:
package com.zyz;import org.apache.dubbo.config.annotation.Reference;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplicationpublic class DubboConsumerDemo { @Reference(version = "default") private DemoService demoService; public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(DubboConsumerDemo.class); DemoService demoService = context.getBean(DemoService.class); System.out.println((demoService.sayHello("zyz"))); }}配置文件application.yml:
spring: application: name: dubbo-consumer-demoserver: port: 8082dubbo: registry: address: zookeeper://127.0.0.1:2181先启动Zookeeper,再启动provider的启动类,最后启动consumer的启动类
看到输出:
dubbo:20880, Hello, zyz大功告成。
Dubbo提供了四种负载均衡策略,也可以自定义。
修改provider的配置文件为:
# Spring boot applicationspring.application.name=dubbo-provider-demoserver.port=8081# Base packages to scan Dubbo Component: @org.apache.dubbo.config.annotation.Servicedubbo.scan.base-packages=com.zyz.provider.servicedubbo.application.name=${spring.application.name}## Dubbo Registrydubbo.registry.address=zookeeper://127.0.0.1:2181# Dubbo Protocol#dubbo.protocol.name=dubbo#dubbo.protocol.port=20880dubbo.protocols.p1.id=dubbo1dubbo.protocols.p1.name=dubbodubbo.protocols.p1.port=20881dubbo.protocols.p1.host=0.0.0.0dubbo.protocols.p2.id=dubbo2dubbo.protocols.p2.name=dubbodubbo.protocols.p2.port=20882dubbo.protocols.p2.host=0.0.0.0dubbo.protocols.p3.id=dubbo3dubbo.protocols.p3.name=dubbodubbo.protocols.p3.port=20883dubbo.protocols.p3.host=0.0.0.0服务消费端新增类:
package com.zyz.consumer;import com.zyz.DemoService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;@EnableAutoConfigurationpublic class LoadBalanceDubboConsumerDemo { @Reference(version = "default", loadbalance = "roundrobin") private DemoService demoService; public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(LoadBalanceDubboConsumerDemo.class); DemoService demoService = context.getBean(DemoService.class); roundRobin(demoService); } /** * 负载均衡(轮询)
* @param demoService
*/
public static void roundRobin(DemoService demoService){ for (int i = 0; i < 1000; i++) { System.out.println((demoService.sayHello("zyz"))); try { Thread.sleep(1 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } }}最终输出为:
dubbo:20882, Hello, zyzdubbo:20883, Hello, zyzdubbo:20881, Hello, zyzdubbo:20882, Hello, zyzdubbo:20883, Hello, zyzdubbo:20881, Hello, zyz在服务提供者和服务消费者上都可以配置服务超时时间,这两者是不⼀样的。
消费者调⽤⼀个服务,分为三步:
如果在服务端和消费端只在其中⼀⽅配置了timeout,那么没有歧义,表示消费端调⽤服务的超时时间,消
费端如果超过时间还没有收到响应结果,则消费端会抛超时异常,但,服务端不会抛异常,服务端在执⾏
服务后,会检查执⾏该服务的时间,如果超过timeout,则会打印⼀个超时⽇志。服务会正常的执⾏完。
如果在服务端和消费端各配了⼀个timeout,那就⽐较复杂了,假设
那么消费端调⽤服务时,消费端会收到超时异常(因为消费端超时了),服务端⼀切正常(服务端没有超时)。
服务提供方新增两个类:
package com.zyz.provider.service;import com.zyz.DemoService;import org.apache.dubbo.common.URL;import org.apache.dubbo.config.annotation.Service;import org.apache.dubbo.rpc.RpcContext;import java.util.concurrent.TimeUnit;@Service(version = "timeout", timeout = 6000)public class TimeoutDemoService implements DemoService { @Override public String sayHello(String name) { System.out.println("执行了timeout服务" + name); // 服务执行5秒 // 服务超时时间为3秒,但是执行了5秒,服务端会把任务执行完的 // 服务的超时时间,是指如果服务执行时间超过了指定的超时时间则会抛一个warn try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("执行结束" + name); URL url = RpcContext.getContext().getUrl(); return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问 }}package com.zyz;import org.apache.dubbo.config.spring.ServiceBean;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;import org.springframework.stereotype.Component;@Componentpublic class UpdateBeanPostProcessors implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (beanName.contains("ServiceBean")) { //这里设置id,否则会造成同一个Service有多个group时,只能注入第一个service ServiceBean serviceBean = (ServiceBean) bean; serviceBean.setId(beanName); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }}消费方新增一个启动类:
package com.zyz.consumer;import com.zyz.DemoService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;@EnableAutoConfigurationpublic class TimeoutDubboConsumerDemo { @Reference(version = "timeout", timeout = 3000) private DemoService demoService; public static void main(String[] args) throws IOException { ConfigurableApplicationContext context = SpringApplication.run(TimeoutDubboConsumerDemo.class); DemoService demoService = context.getBean(DemoService.class); // 服务调用超时时间为1秒,默认为3秒 // 如果这1秒内没有收到服务结果,则会报错 System.out.println((demoService.sayHello("周瑜"))); //xxservestub }}集群容错表示:服务消费者在调⽤某个服务时,这个服务有多个服务提供者,在经过负载均衡后选出其中
⼀个服务提供者之后进⾏调⽤,但调⽤报错后,Dubbo所采取的后续处理策略。
cousumer新增一个类:
package com.zyz.consumer;import com.zyz.DemoService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;@EnableAutoConfigurationpublic class ClusterDubboConsumerDemo { @Reference(version = "cluster", timeout = 1000, cluster = "failfast") private DemoService demoService; public static void main(String[] args) throws IOException { ConfigurableApplicationContext context = SpringApplication.run(ClusterDubboConsumerDemo.class); DemoService demoService = context.getBean(DemoService.class); System.out.println((demoService.sayHello("zyz"))); }}provider新增一个实现类:
package com.zyz.provider.service;import com.zyz.DemoService;import org.apache.dubbo.common.URL;import org.apache.dubbo.config.annotation.Service;import org.apache.dubbo.rpc.RpcContext;import java.util.concurrent.TimeUnit;@Service(version = "cluster", timeout = 3000)public class ClusterDemoService implements DemoService { @Override public String sayHello(String name) { System.out.println("执行了cluster服务" + name); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("执行结束" + name); URL url = RpcContext.getContext().getUrl(); return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问 }}服务降级表示:服务消费者在调⽤某个服务提供者时,如果该服务提供者报错了,所采取的措施。
集群容错和服务降级的区别在于:
consumer新增一个类:
package com.zyz.consumer;import com.zyz.DemoService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;@EnableAutoConfigurationpublic class MockDubboConsumerDemo { @Reference(version = "timeout", timeout = 1000, mock = "fail: return 123") private DemoService demoService; public static void main(String[] args) throws IOException { ConfigurableApplicationContext context = SpringApplication.run(MockDubboConsumerDemo.class); DemoService demoService = context.getBean(DemoService.class); System.out.println((demoService.sayHello("zyz"))); }}本地存根就是⼀段逻辑,这段逻辑是在服务消费端执⾏的,
这段逻辑⼀般都是由服务提供者提供,服务提供者可以利⽤这种机制在服务消费者远程调⽤服务提供者之前或之后再做⼀些其他事情,⽐如结果缓存,请求参数验证等等。(AOP功能)
interface新增一个类:
package com.zyz;public class DemoServiceStub implements DemoService { private final DemoService demoService; // 构造函数传入真正的远程代理对象 public DemoServiceStub(DemoService demoService){ this.demoService = demoService; } @Override public String sayHello(String name) { // 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等 try { System.out.println("校验逻辑"); return demoService.sayHello(name); // safe null } catch (Exception e) { // 你可以容错,可以做任何AOP拦截事项 return "容错数据"; } }}consumer新增一个类:
package com.zyz.consumer;import com.zyz.DemoService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;@EnableAutoConfigurationpublic class StubDubboConsumerDemo { @Reference(version = "timeout", timeout = 1000, stub = "com.zyz.DemoServiceStub") private DemoService demoService; public static void main(String[] args) throws IOException { ConfigurableApplicationContext context = SpringApplication.run(StubDubboConsumerDemo.class); DemoService demoService = context.getBean(DemoService.class); System.out.println((demoService.sayHello("周瑜"))); }}就是Mock功能,Mock其实就是Dubbo中的服务容错的解决⽅案。
⾸先,如果当前服务⽀持参数回调,意思就是:对于某个服务接⼝中的某个⽅法,如果想⽀持消费者在调
⽤这个⽅法时能设置回调逻辑,那么该⽅法就需要提供⼀个⼊参⽤来表示回调逻辑。
因为Dubbo协议是基于⻓连接的,所以消费端在两次调⽤同⼀个⽅法时想指定不同的回调逻辑,那么就需 要在调⽤时在指定⼀定key进⾏区分。
consumer新增两个类
package com.zyz.consumer;import com.zyz.DemoServiceListener;public class DemoServiceListenerImpl implements DemoServiceListener { @Override public void changed(String msg) { System.out.println("被回调了:"+msg); }}package com.zyz.consumer;import com.zyz.DemoService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;@EnableAutoConfigurationpublic class CallbackDubboConsumerDemo { @Reference(version = "callback") private DemoService demoService; public static void main(String[] args) throws IOException { ConfigurableApplicationContext context = SpringApplication.run(CallbackDubboConsumerDemo.class); DemoService demoService = context.getBean(DemoService.class); // 用来进行callback System.out.println(demoService.sayHello("zyz", "d1", new DemoServiceListenerImpl())); System.out.println(demoService.sayHello("zyz", "d2", new DemoServiceListenerImpl())); System.out.println(demoService.sayHello("zyz", "d3", new DemoServiceListenerImpl())); }}interface新增一个类,并在DemoService中新增方法:
package com.zyz;public interface DemoService { String sayHello(String name); // 添加回调 default String sayHello(String name, String key, DemoServiceListener listener) { return null; };}package com.zyz;public interface DemoServiceListener { void changed(String msg);}provider新增类:
package com.zyz.provider.service;import com.zyz.DemoService;import com.zyz.DemoServiceListener;import org.apache.dubbo.common.URL;import org.apache.dubbo.config.annotation.Argument;import org.apache.dubbo.config.annotation.Method;import org.apache.dubbo.config.annotation.Service;import org.apache.dubbo.rpc.RpcContext;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;// DemoService的sayHello方法的index=1的参数是回调对象,服务消费者可以调用addListener方法来添加回调对象,服务提供者一旦执行回调对象的方法就会通知给服务消费者@Service(version = "callback", methods = {@Method(name = "sayHello", arguments = {@Argument(index = 2, callback = true)})}, callbacks = 3)public class CallBackDemoService implements DemoService { private final Map<String, DemoServiceListener> listeners = new ConcurrentHashMap<String, DemoServiceListener>(); public CallBackDemoService() { Thread t = new Thread(new Runnable() { @Override public void run() { while (true) { for (Map.Entry<String, DemoServiceListener> entry : listeners.entrySet()) { entry.getValue().changed(getChanged(entry.getKey())); } try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }); t.start(); } private String getChanged(String key) { return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); } @Override public String sayHello(String name) { return null; } @Override public String sayHello(String name, String key, DemoServiceListener callback) { System.out.println("执行了回调服务" + name); listeners.put(key, callback); URL url = RpcContext.getContext().getUrl(); return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问 }}从 2.7.0 开始,Dubbo 的所有异步编程接口开始以 CompletableFuture 为基础
基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。
consumer新增类:
package com.zyz.consumer;import com.zyz.DemoService;import org.apache.dubbo.config.annotation.Reference;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;import java.util.concurrent.CompletableFuture;@EnableAutoConfigurationpublic class AsyncDubboConsumerDemo { @Reference(version = "async") private DemoService demoService; public static void main(String[] args) throws IOException { ConfigurableApplicationContext context = SpringApplication.run(AsyncDubboConsumerDemo.class); DemoService demoService = context.getBean(DemoService.class); // 调用直接返回CompletableFuture CompletableFuture<String> future = demoService.sayHelloAsync("异步调用"); // 5 future.whenComplete((v, t) -> { if (t != null) { t.printStackTrace(); } else { System.out.println("Response: " + v); } }); System.out.println("结束了"); }}interface中DemoService新增方法:
package com.zyz;import java.util.concurrent.CompletableFuture;public interface DemoService { String sayHello(String name); // 异步调用方法 default CompletableFuture<String> sayHelloAsync(String name) { return null; }; // 添加回调 default String sayHello(String name, String key, DemoServiceListener listener) { return null; };}consumer新增一个类:
package com.zyz.provider.service;import com.zyz.DemoService;import org.apache.dubbo.common.URL;import org.apache.dubbo.config.annotation.Service;import org.apache.dubbo.rpc.RpcContext;import java.util.concurrent.CompletableFuture;@Service(version = "async")public class AsyncDemoService implements DemoService { @Override public String sayHello(String name) { System.out.println("执行了同步服务" + name); URL url = RpcContext.getContext().getUrl(); return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问 } @Override public CompletableFuture<String> sayHelloAsync(String name) { System.out.println("执行了异步服务" + name); return CompletableFuture.supplyAsync(() -> { return sayHello(name); }); }}泛化调⽤可以⽤来做服务测试。
在Dubbo中,如果某个服务想要⽀持泛化调⽤,就可以将该服务的generic属性设置为true,那对于服务消费者来说,就可以不⽤依赖该服务的接⼝,直接利⽤GenericService接⼝来进⾏服务调⽤。
consumer新增一个类:
package com.zyz.consumer;import org.apache.dubbo.config.annotation.Reference;import org.apache.dubbo.rpc.service.GenericService;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.ConfigurableApplicationContext;import java.io.IOException;@EnableAutoConfigurationpublic class GenericDubboConsumerDemo { @Reference(id = "demoService", version = "default", interfaceName = "com.zyz.DemoService", generic = true) private GenericService genericService; public static void main(String[] args) throws IOException { ConfigurableApplicationContext context = SpringApplication.run(GenericDubboConsumerDemo.class); GenericService genericService = (GenericService) context.getBean("demoService"); Object result = genericService.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{"zyz"}); System.out.println(result); }}provider新增一个类:
package com.zyz.provider.service;import org.apache.dubbo.config.annotation.Service;import org.apache.dubbo.rpc.service.GenericException;import org.apache.dubbo.rpc.service.GenericService;@Service(interfaceName = "com.zyz.DemoService", version = "generic")public class GenericDemoService implements GenericService { @Override public Object $invoke(String s, String[] strings, Object[] objects) throws GenericException { System.out.println("执行了generic服务"); return "执行的方法是" + s; }}管理台(https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-
admin)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。