SpringBoot整合Dubbo

SpringBoot整合Dubbo

1. 创建基础工程

我们创建一个maven工程,假设命名为dubbo05,在该工程下,创建一个模板,假设模板名为dubbo-api
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
创建成功后,在该模板下引入下列依赖:

 <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

模板的目录如下:
在这里插入图片描述
Product.java

@Data
@TableName(value = "shop_product")
public class Product implements Serializable {
    @TableId(type = IdType.AUTO,value = "pid")
    private Integer pid;
    @TableField(value = "pname")
    private String pname;
    @TableField(value = "pprice")
    private Double pprice;
    @TableField(value = "stock")
    private Integer stock;
}

User.java

@Data
@TableName(value = "shop_user")
public class User implements Serializable {
    @TableId(type = IdType.AUTO)
    private Integer id;
    @TableField(value = "username")
    private String username;
    @TableField(value = "password")
    private String password;
    @TableField(value = "telephone")
    private String telephone;
    @TableField(exist = false)
    private List<Product>productList;
}

ResultVO.java

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultVO <T> implements Serializable {
    private Integer code;
    private String msg;
    private T data;
    public ResultVO(Integer code,String msg){
        this.code=code;
        this.msg=msg;
    }
}

注意,上面的类都要实现序列化,因为Dubbo在远程调用时,会进行序列化
ResultVOUtil.java

public class ResultVOUtil {
    public static ResultVO success(){
        return new ResultVO<>(200,"操作成功");
    }
    public static ResultVO success(Object data){
        return new ResultVO<>(200,"操作成功",data);
    }
    public static ResultVO error(Integer code,String msg){
        return new ResultVO<>(code,msg);
    }
}

ProductService.java

public interface ProductService {
    ResultVO getProductById(Integer id);
    ResultVO saveProduct(Product product);
}

UserService.java

public interface UserService {
    ResultVO getUserById(int id);
}

application.yml

spring:
  datasource:
    username: root
    password: 3fa4d180
    url: jdbc:mysql://localhost:3306/young1?useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
  mapper-locations: mapper/*.xml

2. 创建dubbo-provider和dubbo-consumer模板

先启动zookeeper
创建模板的过程在上面演示过了,新建的两个模板导入的依赖都如下:
在这里插入图片描述

<dependencies>
        <dependency>
            <groupId>com.young</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.7.4</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
    </dependencies>

目录结构如下:
在这里插入图片描述
在这里插入图片描述
数据库的内容如下:
在这里插入图片描述
在这里插入图片描述

我们先看dubbo-provider模板
ProductMapper.java

@Mapper
public interface ProductMapper extends BaseMapper<Product> {
}

ProductServicImpl.java

package com.young.dubbo.provider.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.young.dubbo.api.entity.Product;
import com.young.dubbo.api.service.ProductService;
import com.young.dubbo.api.util.ResultVOUtil;
import com.young.dubbo.api.vo.ResultVO;
import com.young.dubbo.provider.mapper.ProductMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Service
@Component
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;
    @Override
    public ResultVO getProductById(Integer id) {
        Product product=productMapper.selectById(id);
        return ResultVOUtil.success(product);
    }
    @Override
    public ResultVO saveProduct(Product product) {
        int addNum=productMapper.insert(product);
        if(addNum<=0){
            return ResultVOUtil.error(400,"添加商品失败");
        }else{
            Map<String,Object>res=new HashMap<>();
            res.put("addNum",addNum);
            res.put("id",product.getPid());
            return ResultVOUtil.success(res);
        }
    }
}

ProviderApplication.java

package com.young.dubbo.provider;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableDubbo
public class ProviderApplication {
    public static void main(String[]args){
        SpringApplication.run(ProviderApplication.class,args);
    }
}

ProviderApplicationTest.java

package com.young.dubbo.provider;

import com.young.dubbo.api.entity.Product;
import com.young.dubbo.api.service.ProductService;
import com.young.dubbo.api.vo.ResultVO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class ProviderApplicationTest {
    @Resource
    private ProductService productService;
    @Test
    public void testGet(){
        ResultVO resultVO=productService.getProductById(1);
        System.out.println(resultVO);
    }
    @Test
    public void testAdd(){
        Product product=new Product();
        product.setPname("魅族");
        product.setPprice(2000.0);
        product.setStock(100);
        ResultVO resultVO=productService.saveProduct(product);
        System.out.println(resultVO);
    }
}

application.yml

server:
  port: 8081
dubbo:
  application:
    name: dubbo-provider
  registry:
    address: zookeeper://127.0.0.1:2181
    protocol: zookeeper
  protocol:
    name: dubbo
    port: 20881
  monitor:
    protocol: registry
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/young1?useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
  mapper-locations: mapper/*.xml

测试ProviderApplicationTest.java的testGet方法和testAdd方法
在这里插入图片描述
在这里插入图片描述
接下来是dubbo-consumer模块
UserMapper.java

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

UserServiceImpl.java

package com.young.dubbo.consumer.service.impl;

import com.young.dubbo.api.entity.User;
import com.young.dubbo.api.service.UserService;
import com.young.dubbo.api.util.ResultVOUtil;
import com.young.dubbo.api.vo.ResultVO;
import com.young.dubbo.consumer.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public ResultVO getUserById(int id) {
        User user=userMapper.selectById(id);
        return ResultVOUtil.success(user);
    }
}

ConsumerApplication.java

package com.young.dubbo.consumer;


import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableDubbo
public class ConsumerApplication {
    public static void main(String[]args){
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

ConsumerApplicationTest.java

package com.young.dubbo.consumer;

import com.young.dubbo.api.entity.User;
import com.young.dubbo.api.service.UserService;
import com.young.dubbo.api.vo.ResultVO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ConsumerApplicationTest {
    @Autowired
    private UserService userService;
    @Test
    public void testGet(){
        ResultVO resultVO=userService.getUserById(1);
        System.out.println(resultVO);
    }
}

application.yml

server:
  port: 8082
dubbo:
  application:
    name: dubbo-consumer
  registry:
    address: zookeeper://127.0.0.1:2181
  protocol:
    name: dubbo
    port: 20882
  monitor:
    protocol: registry
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/young1?useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
  mapper-locations: mapper/*.xml

测试testGet方法
在这里插入图片描述

3.整合Dubbo

在上面的步骤都没问题时,我们可以确定数据库能正常访问,接下来假设我们要在UserServiceImpl中,调用ProductService来获取商品信息,具体操作如下

package com.young.dubbo.consumer.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.young.dubbo.api.entity.Product;
import com.young.dubbo.api.entity.User;
import com.young.dubbo.api.service.ProductService;
import com.young.dubbo.api.service.UserService;
import com.young.dubbo.api.util.ResultVOUtil;
import com.young.dubbo.api.vo.ResultVO;
import com.young.dubbo.consumer.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class UserServiceImpl implements UserService {
    @Reference
    private ProductService productService;
    @Autowired
    private UserMapper userMapper;
    @Override
    public ResultVO getUserById(int id) {
        User user=userMapper.selectById(id);
        Product product1=(Product) productService.getProductById(1).getData();
        Product product2=(Product) productService.getProductById(2).getData();
        user.setProductList(Arrays.asList(product1,product2));
        return ResultVOUtil.success(user);
    }
}

我们注意到,ProductServiceImpl类上用到的Service注解,引入的是
在这里插入图片描述
我们在dubbo-consumer下,在创建一个controller软件包,在该包下创建UserController.java

package com.young.dubbo.consumer.controller;

import com.young.dubbo.api.service.UserService;
import com.young.dubbo.api.util.ResultVOUtil;
import com.young.dubbo.api.vo.ResultVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class UserController {
    @Resource
    private UserService userService;
    @GetMapping("/getUserById/{id}")
    public ResultVO getUserById(@PathVariable(value = "id",required = true)Integer id){
        return userService.getUserById(id);
    }
}

接下来先运行dubbo-provider项目,在dubbo-consumer项目,然后访问http://localhost:8082/getUserById/1
在这里插入图片描述
整合成功!

4.设置超时时间和重试

我们先修改ProductServiceImpl.java,模拟网络延迟

@Service
@Component
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;
    @Override
    public ResultVO getProductById(Integer id) {
        try{
            Thread.sleep(3000);
        }catch (Exception e){
            e.printStackTrace();
        }
        Product product=productMapper.selectById(id);
        return ResultVOUtil.success(product);
    }
    @Override
    public ResultVO saveProduct(Product product) {
        int addNum=productMapper.insert(product);
        if(addNum<=0){
            return ResultVOUtil.error(400,"添加商品失败");
        }else{
            Map<String,Object>res=new HashMap<>();
            res.put("addNum",addNum);
            res.put("id",product.getPid());
            return ResultVOUtil.success(res);
        }
    }
}

接着重新运行项目,访问http://localhost:8082/getUserById/1
在这里插入图片描述
在这里插入图片描述
这里提示超时了,这是因为dubbo默认的超时时间为1秒,我们将进一步修改ProductServiceImpl.java,设置超时时间为4秒

@Service(timeout = 4000)
@Component
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;
    @Override
    public ResultVO getProductById(Integer id) {
        try{
            Thread.sleep(3000);
        }catch (Exception e){
            e.printStackTrace();
        }
        Product product=productMapper.selectById(id);
        return ResultVOUtil.success(product);
    }
    @Override
    public ResultVO saveProduct(Product product) {
        int addNum=productMapper.insert(product);
        if(addNum<=0){
            return ResultVOUtil.error(400,"添加商品失败");
        }else{
            Map<String,Object>res=new HashMap<>();
            res.put("addNum",addNum);
            res.put("id",product.getPid());
            return ResultVOUtil.success(res);
        }
    }
}

重新访问http://localhost:8082/getUserById/1,大概6秒后返回结果
在这里插入图片描述
我们重新修改ProductServicImpl.java,设置重试次数为4次,超时时间为1秒

Service(timeout = 1000,retries = 4)
@Component
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;
    @Override
    public ResultVO getProductById(Integer id) {
        System.out.println("---------getProductById-----------");
        try{
            Thread.sleep(3000);
        }catch (Exception e){
            e.printStackTrace();
        }
        Product product=productMapper.selectById(id);
        return ResultVOUtil.success(product);
    }
    @Override
    public ResultVO saveProduct(Product product) {
        int addNum=productMapper.insert(product);
        if(addNum<=0){
            return ResultVOUtil.error(400,"添加商品失败");
        }else{
            Map<String,Object>res=new HashMap<>();
            res.put("addNum",addNum);
            res.put("id",product.getPid());
            return ResultVOUtil.success(res);
        }
    }
}

重新访问http://localhost:8082/getUserById/1
在这里插入图片描述
查看提供方(ProviderApplication)的控制台
在这里插入图片描述
这里再第一次请求失败后,会重试4次,不过因为我们设置的超时时间短于3秒,所有都访问失败

5. 负载均衡方式

我们修改ProviderServiceImpl.java

@Service(timeout = 1000,retries = 4)
@Component
public class ProductServiceImpl implements ProductService {
    @Value("${server.port}")
    private Integer port;
    @Autowired
    private ProductMapper productMapper;
    @Override
    public ResultVO getProductById(Integer id) {
        System.out.println("getProductById:"+port);
        Product product=productMapper.selectById(id);
        return ResultVOUtil.success(product);
    }
    @Override
    public ResultVO saveProduct(Product product) {
        int addNum=productMapper.insert(product);
        if(addNum<=0){
            return ResultVOUtil.error(400,"添加商品失败");
        }else{
            Map<String,Object>res=new HashMap<>();
            res.put("addNum",addNum);
            res.put("id",product.getPid());
            return ResultVOUtil.success(res);
        }
    }
}

先把项目都停掉,点击编辑配置
在这里插入图片描述
选择ProviderApplication,点击添加VM选项
在这里插入图片描述
在这里插入图片描述
复制两个ProviderApplication,然后把端口分别改为9002和9003
在这里插入图片描述
在这里插入图片描述
ProviderApplication
在这里插入图片描述
ProviderApplication2
在这里插入图片描述
ProviderApplication3
在这里插入图片描述
然后运行ConsumerApplication
然后多次访问http://localhost:8082/getUserById/1
查看控制台
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以发现,默认使用的负载均衡是随机的,我们可以修改UserServiceImpl来使用轮询的方法

@Component
public class UserServiceImpl implements UserService {
    @Reference(loadbalance = "roundrobin")
    private ProductService productService;
    @Autowired
    private UserMapper userMapper;
    @Override
    public ResultVO getUserById(int id) {
        User user=userMapper.selectById(id);
        Product product1=(Product) productService.getProductById(1).getData();
        Product product2=(Product) productService.getProductById(2).getData();
        user.setProductList(Arrays.asList(product1,product2));
        return ResultVOUtil.success(user);
    }
}

重新启动ConsumerApplication,多次访问
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.宕机

我们把ProviderApplication2和ProviderApplication3都关闭,然后把zookeeper也停掉,此时再访问http://localhost:8082/getUserById/1
在这里插入图片描述
发现依然能访问成功,这是因为虽然zookeeper停了,但是我们的服务有缓存,也就是说,即使没有注册中心,我们也可以通过这个缓存,去得知我们需要的服务在哪个位置,然后再去请求,这体现了Dubbo的高可用性

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值