Springboot2(31)集成dubbo整合--三种实现方法和一些常用配置讲解

源码地址

springboot2教程系列

Dubbo官网资料

SpringBoot与dubbo整合的三种方式

1)导入dubbo-starter,在application.properties配置属性,使用@Service【暴露服务】使用@Reference【引用服务】,使用@EnableDubbo注解。但是没有提供dubbo:method标签的对应注解

2)保留dubbo xml配置文件,导入dubbo-starter,使用@ImportResource导入dubbo的配置文件即可。不再使用@Service【暴露服务】使用@Reference【引用服务】,不使用@EnableDubbo注解。

3)使用注解API的方式,将每一个组件手动创建到容器中,让dubbo来扫描其他的组件,使用@Service【暴露服务】使用@Reference【引用服务】,使用@EnableDubbo注解。

第一种实现

添加maven依赖

        
		
			com.alibaba.spring.boot
			dubbo-spring-boot-starter
			2.0.0
		

		
			org.apache.zookeeper
			zookeeper
			3.4.8
			
				
					org.slf4j
					slf4j-log4j12
				
				
					org.slf4j
					slf4j-api
				
			
		

		
			com.github.sgroschupf
			zkclient
			0.1
		

提供者

定义接口

public interface RemoteUserService {
    String sayHello(String name);
}

接口实现

@Component
@Service(version = "2.6.0",timeout = 10000,interfaceClass = RemoteUserService.class)
public class RemoteUserServiceImpl implements  RemoteUserService {

    @Value("${server.port}")
    private Integer port;

    @Override
    public String sayHello(String name) {
        System.out.println("provider");
        return "hi!server port:"+port+";name="+name;
    }
}

启动类添加@EnableDubboConfiguration

消费者

@RestController
public class RemoteUserController {
    @Reference(version = "2.7.0",async=true,sent=false)
    private RemoteUserService remoteUser;
}

启动类添加@EnableDubboConfiguration

配置文件

# Tomcat
server:
    tomcat:
        max-threads: 1000
        min-spare-threads: 10
    port: 8091

spring:
     dubbo:
             appname: consumer
             registry: zookeeper://10.10.2.138:2181?backup=10.10.2.139:2181,10.10.2.137:2181
             protocol:
                    name: dubbo
                    port: 20883
#启动时检查(check),关闭所有服务的启动时检查     @Reference(check = false)
spring.dubbo.consumer.check: false
#超时(timeout,默认为1000),    @Reference(timeout=XXX)
spring.dubbo.consumer.timeout: 10000 
#超时后,重试次数(retries)      @Reference(retries=XXX)
spring.dubbo.consumer.retries: 1

#是否注册服务
spring.dubbo.server: false
spring.application.name: dubbo-consumer

第二种实现

启动类

@SpringBootApplication
@ImportResource(value = {"classpath:dubbo.xml"})
@EnableDubbo
public class DubboProviderXMLApplication {
	
	public static void main(String[] args){
        SpringApplication app = new SpringApplication(DubboProviderXMLApplication.class);
       // app.setWebEnvironment(false);
        app.run(args);
     }
}

dubbo.xml放到resources目录下


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://code.alibabatech.com/schema/dubbo
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    
    
    <dubbo:application name="dubbo-provider" owner="dubbo-provider" />

    
    <dubbo:registry protocol="zookeeper" address="zookeeper://10.10.2.138:2181?backup=10.10.2.139:2181,10.10.2.137:2181" client="zkclient" />

    
    <dubbo:protocol name="dubbo" port="20889" />

    
    <dubbo:service interface="cn.myframe.service.RemoteUserService"
                   ref="user2Service" timeout="10000" />

beans>

第三种实现

提供者

@Component
public class ProviderDubboConfig {

    @Autowired(required = false)
    RemoteUserService userService;

    @Autowired(required = false)
    DubboProperties dubboProperties;

    @PostConstruct
    public void userServiceConfig(){
        ServiceConfig<RemoteUserService> serviceConfig = new ServiceConfig<>();
        serviceConfig.setInterface(RemoteUserService.class);
        serviceConfig.setRef(userService);
        serviceConfig.setVersion("2.6.0");
        serviceConfig.setApplication(dubboProperties.getApplication());
        serviceConfig.setRegistry(dubboProperties.getRegistry());
        serviceConfig.setProtocol(dubboProperties.getProtocol());
       // serviceConfig.setProtocols(dubboProperties.getProtocols());

        //配置每一个method的信息
        MethodConfig methodConfig = new MethodConfig();
        methodConfig.setName("sayHello");
        methodConfig.setTimeout(1000);

        //将method的设置关联到service配置中
        List<MethodConfig> methods = new ArrayList<>();
        methods.add(methodConfig);
        serviceConfig.setMethods(methods);
        serviceConfig.export();
       // return serviceConfig;
    }

}

消息者

@Autowired
DubboProperties dubboProperties; 

@Bean
public RemoteUserService remoteUserService(){
    ReferenceConfig<RemoteUserService> referenceConfig = new ReferenceConfig<>();
    referenceConfig.setInterface(RemoteUserService.class);
    referenceConfig.setTimeout(5000);
    referenceConfig.setVersion("2.6.0");
    referenceConfig.setRetries(3);
    referenceConfig.setCheck(false);
    referenceConfig.setRegistry(dubboProperties.getRegistry());
    referenceConfig.setApplication(dubboProperties.getApplication());
    return referenceConfig.get();
}

常用配置

启动时检查

spring.dubbo.consumer.check:设置为false时,启动时检查(check),关闭所有服务的启动时检查。设置true时,如果服务没启动,启动会报错。也可以单独给某个接口设置@Reference(check = false),而且覆盖application.yml中的spring.dubbo.consumer.check配置。

集群容错模式

spring.dubbo.consumer.Cluster: 可以自行扩展集群容错策略,@Reference(cluster = "failover ")

failover 失败自动切换 ,默认策略。当出现失败,重试其它服务器 ,spring.dubbo.consumer.retries设置重试次数(不含第一次) 。

failfast快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录

failsafe失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

failback失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

forking并行调用多个服务器,只要一个成功即返回。

broadcast广播调用所有提供者,逐个调用,任意一台报错则报错 。

负载均衡策略

spring.dubbo.consumer.loadbalance: 均衡策略 。@Reference(loadbalance = "roundrobin")

random 随机,按权重设置随机概率 ,缺省

roundrobin轮询,按公约后的权重设置轮询比率。存在慢的提供者累积请求的问题

leastactive最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差 。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大

consistenthash一致性 Hash,相同参数的请求总是发到同一提供者 ,缺省只对第一个参数 Hash

直连提供者

在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者 。

spring.dubbo.consumer.url: dubbo://localhost:20881,或者@Reference(url = "dubbo://localhost:20881")

多协议

application.yml配置,可能配置协议有rmi http

spring:
     dubbo:
             appname: provider
             registry: zookeeper://10.10.2.138:2181?backup=10.10.2.139:2181,10.10.2.137:2181
             protocols:
                 - name: rmi
                   port: 7885
                   hose: 127.0.0.1
                 - name: dubbo
                   port: 28802
                   hose: 127.0.0.1
                 - name: http
                   port: 8500
                   server: servlet  #默认是jetty

同时协议有使用才会有效

@Service(version = "2.7.0",interfaceClass = RemoteUserService.class,protocol={"http","rmi"})

服务分组

当一个接口有多种实现时,可以用 group 区分。

生产者

@Service(version = "2.7.0",group = "service2",timeout = 10000,interfaceClass = RemoteUserService.class)
public class RemoteUserService2Impl implements  RemoteUserService {...}

@Service(version = "2.7.0",group = "service1",timeout = 10000,interfaceClass = RemoteUserService.class)
public class RemoteUserServiceImpl implements  RemoteUserService {...}

消费者

@Reference(version = "2.7.0",group = "*") #任意组

多版本

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。

生产者

@Service(version = "2.6.0",timeout = 10000,interfaceClass = RemoteUserService.class)
public class RemoteUserService2Impl implements  RemoteUserService {...}

@Service(version = "2.7.0",timeout = 10000,interfaceClass = RemoteUserService.class)
public class RemoteUserServiceImpl implements  RemoteUserService {...}

消费者

@Reference(version = "2.7.0") #version="*"  表示任意版本

结果缓存

  • lru 基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。
  • threadlocal 当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。
  • jcache 与 JSR107 集成,可以桥接各种缓存实现。

lru 的缺省cache.size为1000

@Reference(version = "2.7.0",cache = "lru")

异步调用

@Reference(version = "2.7.0",async = true)
  • sent="true" 等待消息发出,消息发送失败将抛出异常。
  • sent="false" 不等待消息发出,将消息放入 IO 队列,即刻返回。
@Reference(version = "2.7.0",async = true,sent = true)

隐式参数

消费者

@RequestMapping(value="/dubbo/attachment/{name}")
public String attachment(@PathVariable("name") String name){
    RpcContext.getContext().setAttachment("name", "1");
    String result=remoteUser.attachment();
    return result;
}

注意:path, group, version, dubbo, token, timeout 几个 key 是保留字段,请使用其它值

参数回调

参数回调方式与调用本地 callback 或 listener 相同,只需要在 Spring 的配置文件中声明哪个参数是 callback 类型即可。Dubbo 将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑 。

服务接口示例

public interface CallbackService {
    void addListener(String key, CallbackListener listener);
}
public interface CallbackListener {
    void changed(String msg);
}
@Component("callbackService")
public class CallbackServiceImpl implements CallbackService{
    public final static Map<String, CallbackListener> listeners =
        new ConcurrentHashMap<String, CallbackListener>();

    public void addListener(String key, CallbackListener listener) {
        listeners.put(key, listener);
        listener.changed("key:"+key+",调用回调方法"); // 发送变更通知
    }

}

服务提供者配置

@PostConstruct
public void callBackrServiceConfig(){
    ServiceConfig<CallbackService> serviceConfig = new ServiceConfig<>();
    serviceConfig.setInterface(CallbackService.class);
    serviceConfig.setRef(callbackService);
    serviceConfig.setVersion("2.6.0");
    serviceConfig.setApplication(dubboProperties.getApplication());
    serviceConfig.setRegistry(dubboProperties.getRegistry());
    serviceConfig.setProtocol(dubboProperties.getProtocol());
    serviceConfig.setCallbacks(100); //设置回调参数个数

    //配置每一个method的信息
    MethodConfig methodConfig = new MethodConfig();
    methodConfig.setName("addListener");

    ArgumentConfig argumentConfig = new ArgumentConfig();
    argumentConfig.setIndex(1);
    argumentConfig.setCallback(true);
    methodConfig.setArguments(Arrays.asList(argumentConfig));

    //将method的设置关联到service配置中
    List<MethodConfig> methods = new ArrayList<>();
    methods.add(methodConfig);
    serviceConfig.setMethods(methods);
    serviceConfig.export();
}

触发回调

@GetMapping("/listener")
public String listener(){
    for(Map.Entry<String, CallbackListener> entry : CallbackServiceImpl.listeners.entrySet()) {
        entry.getValue().changed("key:" + entry.getKey() + ",调用回调方法");
    }
    return "success";
}

服务消费者配置示例

@Reference(version = "2.6.0")
private CallbackService callbackService;

服务消费者调用

@RequestMapping(value="/dubbo/listener/{name}")
public void listener(@PathVariable("name") String name){
    callbackService.addListener(name,new CallbackListener(){
        public void changed(String msg) {
            System.out.println("callback1:" + msg);
        }
    });
}

事件通知

在调用之前、调用之后、出现异常时,会触发 oninvokeonreturnonthrow 三个事件,可以配置当事件发生时

服务提供者与消费者共享服务接口

public interface IDemoService {
    public Project get(String projectName);
}

服务提供者实现

@Component
@Service(version = "2.7.0",timeout = 10000,interfaceClass = IDemoService.class)
public class NormalDemoService implements IDemoService{
    @Override
    public Project get(String projectName) {
        return new Project(projectName);
    }
}

服务消费者 Callback 接口和实现

public interface Notify {
    public void onreturn(Project project, String name);
    public void onthrow(Throwable ex, String name);
}

@Component
public class NotifyImpl implements Notify {

    public Map<String, Project>    ret    = new HashMap<String, Project>();
    public Map<String, Throwable> errors = new HashMap<String, Throwable>();

    public void onreturn(Project project, String name) {
        System.out.println("onreturn:" + project+",name:"+name);
        ret.put(name, project);
    }
    public void onthrow(Throwable ex, String name) {
        errors.put(name, ex);
    }
}

服务消费者 Callback 配置

@Configuration
public class DubboConfig {

    @Autowired
    NotifyImpl notify;

    @Autowired
    DubboProperties dubboProperties;

    @Bean
    public IDemoService demoService(){
        ReferenceConfig<IDemoService> referenceConfig = new ReferenceConfig<>();
        referenceConfig.setInterface(IDemoService.class);
        referenceConfig.setTimeout(5000);
        referenceConfig.setVersion("2.7.0");
        referenceConfig.setRetries(3);
        referenceConfig.setRegistry(dubboProperties.getRegistry());
        referenceConfig.setApplication(dubboProperties.getApplication());

        //配置每一个method的信息
        MethodConfig methodConfig = new MethodConfig();
        methodConfig.setName("get");
        methodConfig.setTimeout(1000);
        methodConfig.setAsync(true);
        methodConfig.setOnreturn(notify);
        methodConfig.setOnreturnMethod("onreturn");
        //将method的设置关联到service配置中
        List<MethodConfig> methods = new ArrayList<>();
        methods.add(methodConfig);
        referenceConfig.setMethods(methods);
        return referenceConfig.get();
    }

}

callbackasync 功能正交分解,async=true 表示结果是否马上返回,onreturn 表示是否需要回调。

两者叠加存在以下几种组合情况 [2]:

  • 异步回调模式:async=true onreturn="xxx"
  • 同步回调模式:async=false onreturn="xxx"
  • 异步无回调 :async=true
  • 同步无回调 :async=false

测试代码

@Autowired
private IDemoService demoService;

@RequestMapping(value="/dubbo/notity/{name}")
public String notity(@PathVariable("name") String name){
    demoService.get(name);
    return "success";
}

本地伪装(服务降级)

通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过 Mock 数据返回授权失败。

@Reference(version = "2.7.0",mock = "cn.myframe.service.MockUserServicImpl")

提供 Mock 实现

public class MockUserServicImpl implements RemoteUserService {
    @Override
    public String sayHello(String name) {
        return "error";
    }
}

调用

@RequestMapping(value="/dubbo/sayhello/{name}")
public String sayHello(@PathVariable("name") String name){
    String result=remoteUser.sayHello(name);
    return result;
}

当提供者服务不可用时,返回error

并发控制

@Service(version = "2.7.0",interfaceClass = RemoteUserService.class,executes=10)

服务器端并发执行(或占用线程池线程数)不能超过 10 个

@Service(version = "2.7.0",interfaceClass = RemoteUserService.class,actives = 10)

每客户端并发执行(或占用连接的请求数)不能超过 10 个

粘滞连接

粘滞连接用于有状态服务,尽可能让客户端总是向同一提供者发起调用,除非该提供者挂了,再连另一台。

 @Reference(sticky = true)

你可能感兴趣的:(springboot2,springboot2)