Router
By creating custom routers, you can implement specific routing methods based on the characteristics of your business scenario.
Prerequisites
Choose one of the two deployment and running methods
Based on Kubernetes
- Install Kubernetes environment
- Modify the configuration file in Provider to enable the address of nacos deployed in Kubernetes
# (The configuration remains the same as in the original documentation)
- Modify the configuration file in Consumer to enable the address of nacos deployed in Kubernetes
# (The configuration remains the same as in the original documentation)
- Deploy Extensibility Router Task
Using Local IDE
- Deploy Nacos version 2.2.0
- Modify the configuration file in Provider to enable the local nacos address
# (The configuration remains the same as in the original documentation)
- Modify the configuration file in Consumer to enable the local nacos address
# (The configuration remains the same as in the original documentation)
Task Details
The task is to stick to the first Provider that starts providing the service. If that Provider goes offline, choose a new Provider.
Implementation Method
Create a custom router in the Consumer. In this router, save the Provider that was used for the first invocation. For subsequent invocations, if the list of Providers includes the one used during the first invocation, continue to use it; otherwise, choose a new Provider.
Code Structure
src
|-main
|-java
|-org
|-apache
|-dubbo
|-samples
|-extensibility
|-router
|-consumer
|-router
|-StickFirstStateRouter.java (Implement StateRouter interface)
|-StickFirstStateRouterFactory.java (Implement StateRouterFactory interface)
|-resources
|-META-INF
|-application.properties (Dubbo Consumer configuration file)
|-dubbo
|-org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory (Plain text file)
Code Details
- StickFirstStateRouter
package org.apache.dubbo.samples.extensibility.router.consumer.router;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;
import org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;
import org.apache.dubbo.rpc.cluster.router.state.BitList;
public class StickFirstStateRouter<T> extends AbstractStateRouter<T> implements ConfigurationListener {
public StickFirstStateRouter(URL url) {
super(url);
}
public static final String NAME = "STICK_FIRST_ROUTER";
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(StickFirstStateRouter.class);
private volatile BitList<Invoker<T>> firstInvokers;
@Override
protected BitList<Invoker<T>> doRoute(BitList<Invoker<T>> invokers, URL url, Invocation invocation, boolean needToPrintMessage, Holder<RouterSnapshotNode<T>> routerSnapshotNodeHolder, Holder<String> messageHolder) throws RpcException {
if (CollectionUtils.isEmpty(invokers)) {
if (needToPrintMessage) {
messageHolder.set("Directly Return. Reason: Invokers from previous router is empty.");
}
return invokers;
}
BitList<Invoker<T>> copy = invokers.clone();
if (CollectionUtils.isEmpty(copy)) {
this.firstInvokers = new BitList<>(BitList.emptyList());
this.firstInvokers.add(copy.get(0));
} else {
this.firstInvokers = copy.and(invokers);
if(CollectionUtils.isEmpty(this.firstInvokers)){
this.firstInvokers.add(copy.get(0));
}
}
return this.firstInvokers;
}
@Override
public void process(ConfigChangedEvent event) {
if (logger.isDebugEnabled()) {
logger.debug("Notification of tag rule, change type is: " + event.getChangeType() + ", raw rule is:\n " +
event.getContent());
}
// Reset
if (event.getChangeType().equals(ConfigChangeType.DELETED)) {
this.firstInvokers = null;
}
}
@Override
public void stop() {
super.stop();
this.firstInvokers = null;
}
}
- StickFirstStateRouterFactory
package org.apache.dubbo.samples.extensibility.router.consumer.router;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;
public class StickFirstStateRouterFactory implements StateRouterFactory {
@Override
public <T> StateRouter<T> getRouter(Class<T> interfaceClass, URL url) {
return new StickFirstStateRouter<>(url);
}
}
SPI Configuration
Add the following configuration to the resources/META-INF/dubbo/org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory
file:
stickfirst=org.apache.dubbo.samples.extensibility.router.consumer.router.StickFirstStateRouterFactory
Configuration File
Add the following configuration to the resources/application.properties
file:
# Configure custom router
dubbo.consumer.router=stickfirst
Execution Results
Run the task using the Using Local IDE method, and the results are as follows:
To summarize, Dubbo’s extensibility allows you to create custom routers, providing a way to customize the routing logic based on your business requirements. This tutorial demonstrates how to create a “Stick to the First Provider” routing strategy, which can be useful for optimizing network traffic and reducing latency.