官网:http://dubbo.apache.org/zh/docs/v2.7/user/ demo项目地址:https://gitee.com/archguide/dubbo-tuling-demo clone地址:https://gitee.com/archguide/dubbo-tuling-demo.git 管理台github地址:https://github.com/apache/dubbo-admin
Dubbo提供了很多功能,这里我们只介绍几种比较重要的,其他功能可以去Dubbo官网上查看。
代码
服务提供者与消费者公共接口
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;
};
}
服务提供者有多个实现类(这里先列举一个实现类,后边边讲边引入其他实现类,每个实现类都由service注解version里的版本来控制)
import com.maltose.DemoService;
import com.maltose.DemoServiceListener;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.rpc.RpcContext;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
//此处的service是dubbo提供的,不是spring里的;在类上加dubbo的service注解,就代表定义了一个dubbo服务
//服务提供者
@Service(version = "1.0.2")
public class DefaultDemoService implements DemoService {
public String sayHello(String name) {
System.out.println("执行了服务" + name);
//得到调用者的信息(包括调用者使用的协议、端口等)
URL url = RpcContext.getContext().getUrl();
//返回的数据
//参数2:使用的协议 参数3:使用的端口
return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问
}
}
服务提供者SpringBoot配置文件application.properties
spring.application.name=dubbo-provider-demo
server.port=8081
#扫描这个路径下的、并且有@Service注解的类
dubbo.scan.base-packages=com.maltose.provider.service
dubbo.application.name=${spring.application.name}
## 配置注册中心
dubbo.registry.address=zookeeper://127.0.0.1:2181
#Protocol:协议
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
# 如果要支持很多协议的话,可以把下边这些注释都打开
#dubbo.protocol.name=rest
#dubbo.protocol.port=8083
dubbo.protocols.p1.id=dubbo1
dubbo.protocols.p1.name=dubbo
dubbo.protocols.p1.port=20881
dubbo.protocols.p1.host=0.0.0.0
dubbo.protocols.p2.id=rest
dubbo.protocols.p2.name=rest
dubbo.protocols.p2.port=8083
dubbo.protocols.p2.host=0.0.0.0
#dubbo.protocols.p3.id=dubbo3
#dubbo.protocols.p3.name=dubbo
#dubbo.protocols.p3.port=20883
#dubbo.protocols.p3.host=0.0.0.0
上边是在应用级别上配置了dubbo支持的协议,如果某一个接口只想支持其中一种协议,那就在注解的service里加配置文件中的协议名称即可
import com.maltose.DemoService;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.RpcContext;
//服务提供者(可以根据不同的业务需求定义不同的group组,每个组下再分不同的版本)
//@Service(version = "1.0.2",group = "order")
@Service(version = "1.0.2")
public class DefaultDemoService implements DemoService {
public String sayHello(String name) {
System.out.println("执行了服务" + name);
//得到调用者的信息(包括调用者使用的协议、端口等)
URL url = RpcContext.getContext().getUrl();
//返回的数据
//参数2:使用的协议 参数3:使用的端口
return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问
}
}
服务消费者(springBoot项目)
import com.maltose.controller.ConsumerInterceptor;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.io.IOException;
//SpringBoot启动类
//WebMvcConfigurer :拦截器(先不管这个,主要看main方法)
@SpringBootApplication
public class DubboConsumerDemo implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ConsumerInterceptor());
}
//通过Version的值来控制调用服务端具体的哪个实现类,如果服务端定义了group组,那这里也可以加group属性的注解
//@Reference(version = "1.0.2", group= "order")
//注意:在其他Controller里想要使用@Autowired注入DemoService的话,必须在启动类里先使用@Reference引入到spring容器;当然在Controller可以直接使用@Reference注解引入DemoService服务即可
//version = "*":代表要调用服务提供者中所有的服务(实现类),会轮询去调用
@Reference(version = "1.0.2")
private DemoService demoService;
public static void main(String[] args) throws IOException {
ConfigurableApplicationContext context = SpringApplication.run(DubboConsumerDemo.class);
DemoService demoService = context.getBean(DemoService.class);
//调用服务端的DemoService 的实现类,但是服务端的实现类有很多,那就要通过Version来控制了
System.out.println((demoService.sayHello("周瑜")));
}
}
消费者配置文件
spring:
application:
name: dubbo-consumer-demo
server:
port: 8082
#dubbo配置zookeeper即可
dubbo:
registry:
address: zookeeper://127.0.0.1:2181
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/loadbalance/
由官网可知,提供了四种负载均衡策略:
在上边服务提供者的配置文件里,支持了三种协议,即相当于同样版本的服务提供者有三个
在服务端注解里配置负载均衡策略
import com.maltose.DemoService;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.rpc.RpcContext;
//loadbalance :提供者配置负载均衡策略
@Service(version = "1.0.2",loadbalance ="roundrobin" )
public class DefaultDemoService implements DemoService {
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); // 正常访问
}
}
消费端也可以配置负载均衡策略
import com.maltose.controller.ConsumerInterceptor;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.io.IOException;
@SpringBootApplication
public class DubboConsumerDemo implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ConsumerInterceptor());
}
//loadbalance :消费者配置负载均衡策略
@Reference(version = "1.0.2", loadbalance = "roundrobin")
private DemoService demoService;
public static void main(String[] args) throws IOException {
ConfigurableApplicationContext context = SpringApplication.run(DubboConsumerDemo.class);
DemoService demoService = context.getBean(DemoService.class);
System.out.println((demoService.sayHello("周瑜")));
}
}
像上边,如果在消费端和服务端都配置了负载均衡策略,以消费端为准(一般只在消费端配置即可)。
这其中比较难理解的就是最少活跃调用数是如何进行统计的?
按道理,最少活跃数应该是在服务提供者端进行统计的,服务提供者统计有多少个请求正在执行中。
但在Dubbo中,就是不讲道理,它是在消费端进行统计的,为什么能在消费端进行统计?
逻辑是这样的:
在服务提供者和服务消费者上都可以配置服务超时时间,这两者是不一样的。
消费者调用一个服务,分为三步:
如果在服务端和消费端只在其中一方配置了timeout,那么没有歧义,表示消费端调用服务的超时时间,消费端如果超过时间还没有收到响应结果,则消费端会抛超时异常,但,服务端不会抛异常,服务端在执行服务后,会检查执行该服务的时间,如果超过timeout,则会打印一个超时日志。服务会正常的执行完。
如果在服务端和消费端各配了一个timeout,那就比较复杂了,假设
那么消费端调用服务时,消费端会收到超时异常(因为消费端超时了),服务端一切正常(服务端没有超时)。
代码
服务提供者配置超时
import com.maltose.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;
//服务提供者配置超时时间6秒
@Service(version = "timeout", timeout = 4000)
public class TimeoutDemoService implements DemoService {
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); // 正常访问
}
}
消费者
import com.maltose.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 {
//消费端配置超时时间3秒
@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
}
}
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/fault-tolerent-strategy/
集群容错表示:服务消费者在调用某个服务时,这个服务有多个服务提供者,在经过负载均衡后选出其中一个服务提供者之后进行调用,但调用报错后,Dubbo所采取的后续处理策略。默认会去重试两次,加上第一次调用,所以报错时总共会调四次;
消费端和服务端都可以配置
import com.maltose.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 {
//消费端配置容错:cluster=failfast:只调用一次,失败后就不重试了
@Reference(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("周瑜")));
}
}
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/service-downgrade/
服务降级表示:服务消费者在调用某个服务提供者时,如果该服务提供者报错了,所采取的措施。
集群容错和服务降级的区别在于:
消费者配置降级
import com.maltose.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 {
//mock:降级,当所调用的服务报错时,自动返回123,而不是出现错误信息
@Reference(version = "timeout", timeout = 1000, mock = "force: 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("周瑜")));
}
}
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/local-stub/
本地存根,名字很抽象,但实际上不难理解,本地存根就是一段逻辑,这段逻辑是在服务消费端执行的,这段逻辑一般都是由服务提供者提供,服务提供者可以利用这种机制在服务消费者远程调用服务提供者之前或之后再做一些其他事情,比如结果缓存,请求参数验证等等。
消费端配置本地存根
import com.maltose.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.maltose.DemoServiceStub")
//本地存根stub:
@Reference(version = "timeout", timeout = 1000, stub = "true")
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("周瑜")));
}
}
定义DemoServiceStub实现DemoService接口
public class DemoServiceStub implements DemoService {
private final DemoService demoService;
// 构造函数传入真正的远程代理对象
public DemoServiceStub(DemoService demoService){
this.demoService = demoService;
}
@Override
public String sayHello(String name) {
// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
try {
return demoService.sayHello(name); // safe null
} catch (Exception e) {
// 你可以容错,可以做任何AOP拦截事项
return "容错数据";
}
}
}
超时后,日志里没有报错,而是打印了"容错数据"
服务端调用流程:由于配置了stub=true,并且当前service是DemoService ,所以dubbo会去自动拼接得到DemoServiceStub这个类,找到后先执行DemoServiceStub里的方法,找不到抛异常;当然了,stub这个值可以自定义一个类,如:
//注意:stub定义的类,必须实现DemoService接口
@Reference(version = "timeout", timeout = 1000, stub = "com.maltose.DemoServiceStub")
private DemoService demoService;
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/local-mock/
本地伪装就是Mock,Dubbo中Mock的功能相对于本地存根更简单一点,Mock其实就是Dubbo中的服务容错的解决方案。
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/callback-parameter/
官网上的Demo其实太复杂,可以看这里的Demo更为简单。
首先,如果当前服务支持参数回调,意思就是:对于某个服务接口中的某个方法,如果想支持消费者在调用这个方法时能设置回调逻辑,那么该方法就需要提供一个入参用来表示回调逻辑。
因为Dubbo协议是基于长连接的,所以消费端在两次调用同一个方法时想指定不同的回调逻辑,那么就需要在调用时再指定一定key进行区分。
代码
接口添加回调
import java.util.concurrent.CompletableFuture;
public interface DemoService {
// 同步调用方法
String sayHello(String name);
// 添加回调
default String sayHello(String name, String key, DemoServiceListener listener) {
return null;
};
}
//用于回调的接口
public interface DemoServiceListener {
void changed(String msg);
}
消费端
public class DemoServiceListenerImpl implements DemoServiceListener {
public void changed(String msg) {
System.out.println("被回调了:"+msg);
}
}
import com.maltose.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);
// 用来进行callback,参数3:回调逻辑,即当前消费端调用完提供者的syHello方法后,服务提供者也可以调用消费者的new DemoServiceListenerImpl里的逻辑(当然服务提供者也可以不调用DemoServiceListenerImpl)
System.out.println(demoService.sayHello("周瑜", "d1", new DemoServiceListenerImpl()));
System.out.println(demoService.sayHello("周瑜", "d2", new DemoServiceListenerImpl()));
System.out.println(demoService.sayHello("周瑜", "d3", new DemoServiceListenerImpl()));
}
}
服务提供者
import com.maltose.DemoService;
import com.maltose.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方法来添加回调对象,服务提供者一旦执行回调对象的方法就会通知给服务消费者
//@Argument(index = 2, callback = true):DemoService有两个sayHello方法,这里要求sayHello方法的下标是2(第三个参数)的参数要支持callBack回调
//这个服务最大同时支持3个回调
@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() {
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());
}
public String sayHello(String name) {
return null;
}
//参数3:接口代理对象
public String sayHello(String name, String key, DemoServiceListener callback) {
System.out.println("执行了回调服务" + name);
//通过代理对象callback,执行回调,向消费端发送数据
callback.changed("xxxx");
//listeners.put(key, callback);
URL url = RpcContext.getContext().getUrl();
// 正常访问
return String.format("%s:%s, Hello, %s", url.getProtocol(), url.getPort(), name);
}
}
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/async-call/
理解起来比较容易,主要要理解CompletableFuture,如果不理解,就直接把它理解为Future
其他异步调用方式:https://mp.weixin.qq.com/s/U3eyBUy6HBVy-xRw3LGbRQ
代码
接口
import java.util.concurrent.CompletableFuture;
public interface DemoService {
// 同步调用方法
String sayHello(String name);
// 异步调用方法
default CompletableFuture<String> sayHelloAsync(String name) {
return null;
};
}
接口实现
import com.maltose.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", protocol = "p1")
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);
//单独开启一个线程执行sayHello方法
return CompletableFuture.supplyAsync(() -> {
return sayHello(name);
});
}
}
消费端
import com.maltose.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);
// 调用直接返回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("结束了");
}
}
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/generic-reference/
泛化调用可以用来做服务测试。
在Dubbo中,如果某个服务想要支持泛化调用,就可以将该服务的generic属性设置为true,那对于服务消费者来说,就可以不用依赖该服务的接口,直接利用GenericService接口来进行服务调用。
代码
消费端
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.maltose.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[]{"周瑜"});
System.out.println(result);
}
}
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/generic-service/
实现了GenericService接口的就是泛化服务
代码
服务提供者
import com.tuling.DemoService;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.rpc.service.GenericException;
import org.apache.dubbo.rpc.service.GenericService;
@Service(interfaceName = "com.tuling.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;
}
}
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/rest/
注意Dubbo的REST也是Dubbo所支持的一种协议。
当我们一个应用用Dubbo提供了一个服务后,如果消费者没有使用Dubbo框架却也想调用服务,那么这个时候我们就可以让我们应用的服务支持REST协议,这样消费者就可以通过REST形式调用我们的服务了。
注意:如果某个服务只有REST协议可用,那么该服务必须用@Path注解定义访问路径
代码
服务提供者
配置文件
# 支持rest协议
dubbo.protocol.name=rest
import com.tuling.DemoService;
import com.tuling.DemoServiceListener;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.protocol.rest.support.ContentType;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service(version = "rest", protocol = "p2")
@Path("demo")
public class RestDemoService implements DemoService {
@GET
@Path("say")
//返回结果类型
@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
@Override
public String sayHello(@QueryParam("name") String name) {
System.out.println("执行了rest服务" + name);
URL url = RpcContext.getContext().getUrl();
return String.format("%s: %s, Hello, %s", url.getProtocol(), url.getPort(), name); // 正常访问
}
}
此时,在浏览器即可访问上边这个服务了
github地址:https://github.com/apache/dubbo-admin
项目里的dubbo配置信息,都可以在远程管理台来进行配置
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/config-rule/
注意动态配置修改的是服务参数,并不能修改服务的协议、IP、PORT、VERSION、GROUP,因为这5个信息是服务的标识信息,是服务的身份证号,是不能修改的。
官网地址:http://dubbo.apache.org/zh/docs/v2.7/user/examples/routing-rule/
条件路由
不同的消费者只能访问属于自己端口的服务提供者
https://zhuanlan.zhihu.com/p/42671353
Zookeeper可视化客户端下载:
https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip
解压后运行: