This article is a use of Dubbo and lays the foundation for subsequent source code analysis.

1. Easiest to use

We will start with a simple example to show how to build a simple example with Dubbo.

This example includes:

  • Registry (Zookeeper instead)
  • Service provider
  • Service Consumers
  • Interface (interface)

1.1 Project Structure

Create a project and create three modules with the following structure:

1.2 Project Dependency

The overall POM.xml is:

<? The 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" > The < 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 - the boot. Version > 2.3.1. RELEASE < / spring - the boot. Version > < dubo. version>2.7.5</ dubo. 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>Copy the code

The dependencies of consumer are:

<? The 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" > < the parent > < artifactId > Study < / artifactId > < groupId > org. Example < / groupId > < version > 1.0 - the SNAPSHOT < / version > < / parent > <modelVersion>4.0.0</modelVersion> <artifactId> Consumer </artifactId> <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 - the boot - starter < / artifactId > < version > 2.7.5 < / version > < / dependency > < the 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>Copy the code

The dependency of interface is:

<? The 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" > < the parent > < artifactId > Study < / artifactId > < groupId > org. Example < / groupId > < version > 1.0 - the SNAPSHOT < / version > < / parent > <modelVersion>4.0.0</modelVersion> <artifactId>interface</artifactId> <build> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build> </project>Copy the code

The dependency of the provider is:

<? The 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" > < the parent > < artifactId > Study < / artifactId > < groupId > org. Example < / groupId > < version > 1.0 - the SNAPSHOT < / version > < / parent > 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 - the boot - starter < / artifactId > < version > 2.7.5 < / version > < / dependency > < the dependency > < the groupId > org, jboss resteasy < / groupId > < artifactId > resteasy - jaxrs < / artifactId > < version > 3.0.19. The Final < / version > </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> < version > 1.1.0. Final < / version > < / dependency > < the 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>Copy the code

1.3 Specific Code

1.3.1 Service Provider

The @service annotation exposes the Service

The implementation class

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 (" execute service "+ name); sayHello(String name) {system.out.println (" execute service" + name); URL url = RpcContext.getContext().getUrl(); Format ("%s: %s, Hello, %s", url.getProtocol(), url.getPort(), name); }}Copy the code

Start the class

package com.zyz; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DubboProviderDemo { public static void main(String[] args) { SpringApplication.run(DubboProviderDemo.class,args); }}Copy the code

Configuration file application.properties:

# Spring boot application spring.application.name=dubbo-provider-demo server.port=8081 # Base packages to scan Dubbo Component: @org.apache.dubbo.config.annotation.Service dubbo.scan.base-packages=com.zyz.provider.service Dubbo. Application. Name = ${spring. Application. The name} # # dubbo Registry dubbo, Registry. Address = zookeeper: / / 127.0.0.1:2181 # Dubbo Protocol dubbo.protocol.name=dubbo dubbo.protocol.port=20880Copy the code

Log file log4j.properties:

###set log levels###
log4j.rootLogger=info, stdout
###output to the console###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n
Copy the code

1.3.2 interface

Interface class DemoService:

package com.zyz;

public interface DemoService {

    String sayHello(String name);

}

Copy the code

1.3.3 Service consumers

The added version indicates which instance of the implementation class to introduce

Start the class:

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;

@SpringBootApplication
public 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")));
    }

}

Copy the code

Configuration file application.yml:

Spring: application: name: dubbo - consumer - demo server: port: 8082 dubbo: registry: address: zookeeper: / / 127.0.0.1:2181Copy the code

This section describes how to configure Zookeeper

Start Zookeeper, the Provider startup class, and the Consumer startup class

See the output:

Dubbo: 20880, Hello, ZyzCopy the code

And you’re done.

2. Specific application

2.1 Load Balancing

Dubbo provides four load balancing policies, which can also be customized.

  • Random LoadBalance: sets the Random probability based on the weight.
  • RoundRobin LoadBalance: Sets the polling ratio based on the convention weight.
  • LeastActive LoadBalance: minimum number of active calls, random with the same number of active calls.
  • ConsistentHash LoadBalance: a ConsistentHash in which requests with the same parameters are always sent to the same provider.

2.2 Specific Code

Change the provider configuration file to:

# Spring boot application spring.application.name=dubbo-provider-demo server.port=8081 # Base packages to scan Dubbo Component: @org.apache.dubbo.config.annotation.Service dubbo.scan.base-packages=com.zyz.provider.service Dubbo. Application. Name = ${spring. Application. The name} # # dubbo Registry dubbo, Registry. Address = zookeeper: / / 127.0.0.1:2181 # Dubbo Protocol #dubbo.protocol.name=dubbo #dubbo.protocol.port=20880 dubbo.protocols.p1.id=dubbo1 Dubbo. Separate protocols. P1. Name = dubbo dubbo. Separate protocols. (p1) port = 20881 dubbo. Separate protocols. (p1) host = 0.0.0.0 dubbo. Separate protocols. P2. Id = dubbo2 Dubbo. Separate protocols. P2. Name = dubbo dubbo. Separate protocols. P2. Port = 20882 dubbo. Separate protocols. P2. Host = 0.0.0.0 Dubbo. Separate protocols. P3. Id = dubbo3 dubbo. Separate protocols. P3. Name = dubbo dubbo. Separate protocols. P3. Port = 20883 dubbo. Separate protocols. P3. Host = 0.0.0.0Copy the code

New class on service consumer side:

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; @EnableAutoConfiguration public 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(); }}}}Copy the code

The final output is:

Dubbo: 20882, Hello, Zyz Dubbo: 20883, Hello, Zyz Dubbo: 20881, Hello, Zyz Dubbo: 20882, Hello, Zyz Dubbo: Dubbo: 20881, Hello, ZyzCopy the code

2.2 Service Timeout

2.2.1 instructions

The service timeout can be configured on both the service provider and the service consumer, which are different.

A consumer invokes a service in three steps:

  • The consumer sends the request (network transport)
  • The server performs the service
  • Server return response (network transport)

If the client on the server and consumption in a timeout is configured on one side only, so there is no ambiguity, said consumers invoke services timeout, eliminate FeiDuan if more than time haven’t received the response as a result, consumers will timeout exception, but, the server will not throw exceptions, the server after the execution of the service, will check the service time, If timeout is exceeded, a timeout log is printed. The service will complete normally.

If you have a timeout on the server and a timeout on the consumer, it becomes more complicated

  • The service execution is 5s
  • Timeout = 3 s consumer end
  • Server timeout = 6 s

Then when the consumer calls the service, the consumer receives a timeout exception (because the consumer timed out) and the server is fine (the server did not time out).

2.2.2 Specific code

The service provider added two new classes:

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(" execute timeout service "+ name); Timeunit.seconds.sleep (5) warn try {timeunit.seconds.sleep (5) warn try {timeunit.seconds.sleep (5); } catch (InterruptedException e) { e.printStackTrace(); } system.out. println(" end of execution "+ name); URL url = RpcContext.getContext().getUrl(); Format ("%s: %s, Hello, %s", url.getProtocol(), url.getPort(), name); }}Copy the code
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; @Component public class UpdateBeanPostProcessors implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (beanname. contains("ServiceBean")) {// Set this parameter to id. Otherwise, there will be multiple groups in the same Service. Inject only the first service ServiceBean. ServiceBean = (ServiceBean) bean; serviceBean.setId(beanName); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }}Copy the code

Consumer adds a new startup class:

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; @EnableAutoConfiguration public 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); System.out.println((demoservice.sayHello (" week ")))); // If no service result is received within 1 second, an error is reported. //xxservestub } }Copy the code

2.3 Cluster fault tolerance

Cluster fault tolerance refers to the subsequent processing strategy adopted by Dubbo when a service consumer invokes a service that has multiple service providers and selects one of them after load balancing.

2.3.1 set

  • Failover Cluster: specifies the default configuration. Three requests are retried twice
  • Failfast Cluster: fails quickly. An error is reported immediately after the Failfast Cluster is invoked only once. Typically used for non-idempotent writes, such as new records
  • Failsafe Cluster: indicates failure security. If an exception occurs, it is ignored. It is used to write audit logs
  • Failback Cluster: Automatically recovers when a failure occurs. Failed requests are recorded in the background and resent periodically. Typically used for message notification operations
  • Forking Cluster: Calls multiple servers in parallel and returns if one is successful. It is usually used for read operations that require high real-time performance but waste more service resources. The maximum parallel number can be set by forks=”2″.
  • Broadcast Cluster: Broadcasts calls to all providers one by one. An error is reported on any provider. Typically used to notify all providers to update local resource information such as caches or logs.

2.3.2 Specific code

Cousumer adds a new class:

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; @EnableAutoConfiguration public 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"))); }}Copy the code

Provider adds an implementation class:

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(" execute cluster service "+ name); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } system.out. println(" end of execution "+ name); URL url = RpcContext.getContext().getUrl(); Format ("%s: %s, Hello, %s", url.getProtocol(), url.getPort(), name); }}Copy the code

2.4 Service Degradation

Service degradation represents the action that a service consumer takes when invoking a service provider if the service provider reports an error.

The difference between cluster fault tolerance and service degradation is:

  • Cluster fault tolerance is the whole cluster – wide fault tolerance
  • Service degradation is the fault tolerance of a single service provider

2.4.1 Specific code

Add a new consumer class:

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; @EnableAutoConfiguration public 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"))); }}Copy the code

2.5 Local stubs

Local stub is a logic, a logic is in the service consumer side, the logic is usually provided by the service provider, service provider can use this mechanism in the service consumer remote call before or after the service provider to do some other things, such as the cache, the request parameter validation and so on. (AOP)

2.5.1 Specific code

Interface adds a new class:

package com.zyz; public class DemoServiceStub implements DemoService { private final DemoService demoService; // The constructor passes in the real remote proxy object public DemoServiceStub(DemoService DemoService){this. DemoService = DemoService; } Override public String sayHello(String name) {Override public String sayHello(String name) {Override public String sayHello(String name) { Try {system.out.println (" check logic "); return demoService.sayHello(name); // safe null} catch (Exception e) {return "error tolerant data "; }}}Copy the code

Add a new consumer class:

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; @EnableAutoConfiguration public 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. The out. Println ((demoService sayHello (" zhou yu "))); }}Copy the code

2.6 Local Camouflage

Mock is the Mock feature, which is essentially a service fault tolerant solution in Dubbo.

2.7 Parameter Callback

First, if the current service supports parameter callback, this means that a method in a service interface needs to provide an input parameter to represent the callback logic if it wants to allow consumers to set the callback logic when calling the method.

Because the Dubbo protocol is based on the long connection, when the consumer calls the same method twice and wants to specify different callback logic, it needs to specify a certain key during the call to distinguish.

2.7.1 Parameter Callback

There are two new classes for consumer

package com.zyz.consumer; import com.zyz.DemoServiceListener; public class DemoServiceListenerImpl implements DemoServiceListener { @Override public void changed(String msg) { System.out.println(" callback: "+ MSG); }}Copy the code
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; @EnableAutoConfiguration public 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); SayHello ("zyz", "d1", new DemoServiceListenerImpl())); // 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())); }}Copy the code

Add a new class to interface and a new method to DemoService:

package com.zyz; public interface DemoService { String sayHello(String name); Default String sayHello(String Name, String Key, DemoServiceListener Listener) {return null; }; }Copy the code
package com.zyz;

public interface DemoServiceListener {
    void changed(String msg);
}

Copy the code

Provider new class:

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; // The index=1 argument to the sayHello method of DemoService is a callback object. The service consumer can call the addListener method to add the callback object. @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 (" execute callback service "+ name); listeners.put(key, callback); URL url = RpcContext.getContext().getUrl(); Format ("%s: %s, Hello, %s", url.getProtocol(), url.getPort(), name); }}Copy the code

2.8 Asynchronous Invocation

As of 2.7.0, all of Dubbo’s asynchronous programming interfaces began to be based on CompletableFuture

NIO based on non-blocking implementation of parallel invocation, the client does not need to start multithreading to complete the parallel invocation of multiple remote services, relatively less overhead multithreading.

2.8.1 Specific code

New consumer class:

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; @EnableAutoConfiguration public 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); / / call returned directly CompletableFuture CompletableFuture < String > future. = demoService sayHelloAsync (" asynchronous calls "); // 5 future.whenComplete((v, t) -> { if (t ! = null) { t.printStackTrace(); } else { System.out.println("Response: " + v); }}); System.out.println(" end "); }}Copy the code

Add method of DemoService in interface:

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; }; }Copy the code

Add a new consumer class:

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 (" execute synchronization service "+ name); URL url = RpcContext.getContext().getUrl(); Format ("%s: %s, Hello, %s", url.getProtocol(), url.getPort(), name); } @override public CompletableFuture<String> sayHelloAsync(String name) {system.out.println (" execute async service "+ name); return CompletableFuture.supplyAsync(() -> { return sayHello(name); }); }}Copy the code

2.9 Generalization Call

Generalized calls can be used to do service testing.

In Dubbo, if a service wants to support generalized invocations, the generic property of the service can be set to True, so that service consumers can use the GenericService interface to make service invocations without relying on the service interface.

2.9.1 Specific code

Add a new consumer class:

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; @EnableAutoConfiguration public 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); }}Copy the code

Provider adds a new class:

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 (" perform generic service "); Return "executes by" + s; }}Copy the code

3. Tools

Zookeeper visual client management console