springboot整合使用dubbo大体分为三大部分

暴露的API接口(dubbo-interface-API)

服务的提供者(dubbo-service-provider)

服务的消费者(dubbo-service-consumer)

还有就是部署在Linux的Redis服务

下面是实现细节


1.对外暴露的API接口(dubbo-interface-API)

对于接口工程的创建 使用了maven 但没使用任何骨架

目录结构为一个实体类和一个服务接口

实体类的创建要注意实现对象的序列化 (实现Serializable 接口)

public class Student implements Serializable {
    private static final long serialVersionUID = 1245946014621298931L;
    private Integer id;
    private String name;
    private int age;
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public interface StudentService  {
    Student queryStudent(String name);
    int addStudent(Student student);
}


2.服务的提供者(dubbo-service-provider)

对于服务的提供者 这里创建使用了maven的spring Initializr 添加了一大部分的springboot起步依赖 

(mysql驱动 mybatis框架 redis驱动等起步依赖)

 

2.1 处理pom文件

对于<暴露接口工程/dubbo/zookeeper>的依赖还需要手动添加

    <!--公共项目的依赖-->
        <dependency>
            <groupId>XXXXXX.XXXXXX</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!--dubbo起步依赖-->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.8</version>
        </dependency>
        <!--zookeeper依赖-->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-dependencies-zookeeper</artifactId>
            <version>2.7.8</version>
            <type>pom</type>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

框架自动生成pom文件中的一些内容

2.2编写StudentDao接口

StudentDao接口来写业务的查询和添加功能

public interface StudentDao {

    Student selectStudentByName(@Param("name")String name);

    int insertStudent(Student student);

}

@Param("name"):mybatis框架-->使用注解传参

在java代码中把数据内容传入到对应的mapper文件的sql语句中

2.3处理mybatis.xml 文件

实现Dao接口的映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<!--指定dao接口的全限定名称-->
<mapper namespace="xxx.xxxxxxx.Dao.StudentDao">

    <select id="selectStudentByName" resultType="com.xxxxxx.model.Student">
        select * from student where name=#{name}
    </select>

    <insert id="insertStudent">
        insert into student(name ,age) values(#{name},#{age})
    </insert>


</mapper>

2.4处理StudentServer接口的实现类---StudentServerImpl

@DubboService(interfaceClass = StudentService.class,version = "1.0",timeout = 5000)
public class StudentServiceImpl implements StudentService {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private StudentDao studentDao;

    /**
     *
     * @param student
     * @return int
     * 初始值:0
     * 添加成功:1
     * 姓名已存在:2
     * 姓名不能为空:3
     */
    @Override
    public int addStudent(Student student) {
        int result = 0;
        if(student.getName() != null){
            Student stu =studentDao.selectStudentByName(student.getName());
            //应该是student不应该是student.getName() 不然会空指针
            if(stu.getName() != null){
                result = 2;
            }else{
                result =studentDao.insertStudent(student);
            }
        }else {
            result = 3;
        }
        return result;
    }

    //查询时会出现缓存穿透的现象
    @Override
    public Student queryStudent(String name) {
        //对键值分别序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Student.class));

        Student student = null;
        final String USER_KEY="STUDENT:";

        if(name != null){
            String key = USER_KEY + name;
            student = (Student) redisTemplate.opsForValue().get(key);
            System.out.println("从redis查数据" + student);
            if(student == null){
                student = studentDao.selectStudentByName(name);
                System.out.println("从数据库查数据" + student);
                if(student != null){
                    redisTemplate.opsForValue().set(key,student);
                }else {
                    redisTemplate.opsForValue().set(key,Student.defaultStudent());
                }
            }
        }
        return student;
    }

}
@DubboService(interfaceClass = StudentService.class,version = "1.0",timeout = 5000)
实现dubbo服务 设置需要的暴露的公共项目 版本号 超时等属性

@Resource:private RedisTemplate redisTemplate;
使用redis需要的注解 通过RedisTemplate封装好的各种方法来操作Redis 进行序列化 反序列化等 

@Resource:private StudentDao studentDao;
spring实现自动注入

2.5处理application.properties文件

#配置dubbo
spring.application.name=dubbo-provider
dubbo.scan.base-packages=xxx.xxxxxxx.service
dubbo.registry.address=zookeeper://localhost:2181

#配置redis
#redis部署在Linux上 使用虚拟机的ip 未使用密码
spring.redis.host=192.168.xxx.xxx
spring.redis.port=6379

#配置mybatis
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

#配置mysql数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=xxxx

mybatis.mapper-locations=classpath:mapper/*.xml
---->通过主配置文件使mybatis找到mapper文件的位置

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
配置mybatis的日志 这里直接配置输出在控制台上

2.6 处理springboot主启动项

@SpringBootApplication
@EnableDubbo
@MapperScan(basePackages = "com.xxxxxx.Dao")
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}
@SpringBootApplication
使用springboot核心注解(复合注解)

@EnableDubbo
启用dubbo服务

@MapperScan(basePackages = "com.xxxxxx.Dao")
(使用mybatis时 把Dao接口与java文件分开存储) 使用注解对包进行扫描
---->通过springboot主类找到接口位置 

3.服务的消费者(dubbo-service-consumer)

提供者提供了接口 消费者就要调用服务提供者提供的接口服务 

3.1处理pom文件

作为dubbo的消费者 这里的pom文件只需要手动添加一个dubbo的依赖和接口的依赖即可 

3.2处理application.properties文件

#指定端口号
server.port=8081
server.servlet.context-path=/test

#配置dubbo
spring.application.name=dubbo-consumer
dubbo.scan.base-packages="com.xxxxxxx.controller"
dubbo.registry.address=zookeeper://localhost:2181

配置文件指定了服务的端口号和服务上下文的资源路径

使用到了dubbo的zookeeper注册中心服务

3.3处理前端控制层的DubboController

@RestController
public class DubboController {

    @DubboReference(interfaceClass = StudentService.class,version = "1.0")
    private StudentService studentService;

    @PostMapping("/student/add")
    public String addStudent(Student student){

        String message = "处理";

        int result = studentService.addStudent(student);
        if(result == 1){
            message="添加成功:"+student.getName();
        }else if (result == 2){
            message="用户信息已存在";
        }else if(result == 3){
            message ="用户不能为空";
        }
        return "添加结果:" + message;
    }
    @GetMapping("/student/query")
    public String queryStudent(String name){

        String message = "";
        Student student = null;

        if(name != null){
            student = studentService.queryStudent(name);
            if(student != null){
                message = "学生信息为:" + student.toString();
            }else {
                message = "未查询到信息!";
            }
        }else{
            message = "查询到信息不能为空!";
        }
        return message;
    }
}

@RestController(复合注解):

RESTful风格的注解 表示@Controller与@ResponseBody的组合,在类的上面使用@RestController , 表示当前类者的所有方法都加入了 @ResponseBody

 @DubboReference(interfaceClass = StudentService.class,version = "1.0"):

实现dubbo服务 调用暴露的公共项目 版本号 等属性

   @PostMapping("/student/add")

RESTful风格的注解  表示支持post请求方式 ,等同于 @RequestMapping( method=RequestMethod.POST)

@GetMapping("/student/query")

RESTful风格的注解 表示支持的get请求方式, 等同于 @RequestMapping( method=RequestMethod.GET)

4.zookeeper + Redis + Linux

4.1启动zookeeper

三大模块写完之后启动zookeeper  执行bin目录下的zkServer.cmd文件 启动zookeeper服务

4.2启动Linux与Redis服务

Linux选择了部署在虚拟机上 虚拟机软件使用的是VMware Linux系统为CentOS 

通过(redis-server)命令启动redis服务 同时也指定了配置文件启动+后台启动 (redis.conf  &)

服务启动之后通过(ps -mf|grep redis)来查看Redis服务是否执行


4.2.2关闭了Linux防火墙

因为不是本地在使用redis服务 所以我先关闭了Linux防火墙

(CentOS7这个版本的防火墙默认使用的是firewall ​与之前的版本Centos 6.x使用iptables不一样)

通过 (systemctl status firewalld) 查看防火墙状态 (service firewalld stop) 关闭防火墙 


4.2.3再给redis.conf配置文件中配置一些重要信息 

第一点:指定输出的日志文件

通过vim编辑器 (vim redis.conf)打开redis.conf文件 再使用(:/log)文件进行关键字查找 指定日志输出的文件 这里指定了redis-log.log文件作为日志输出文件

 第二点:修改redis的默认bind地址

因为连接Redis服务不是在本地 所以需要修改bind地址(默认为127.0.0.1 限制了只有本地连接 所以软件连接不上)

可以直接把这行注释掉或者改成0.0.0.0

第三点:关闭redis的保护模式

Redis默认的保护模式protected-mod 为yes 改为no

(或者可以为redis设置密码 但是Redis便捷高效的特点不建议这么做)

(第四点:指定Redis服务的端口号)

在前面配置的application.properties配置文件中配置了Redis的端口号 如果不是默认端口号6379 需要自行更改

配置信息与防火墙全部设置好后 Redis服务即可成功部署在Linux系统上了


5.测试结果

先启动了zookeeper和Linux上的redis

再从idea中先启动provider的服务在启动consumer服务

打开postman进行测试

使用postman进行了两次测试查询 从idea的日志可以看出第一次查询是先从redis缓存中查数据没查到 又去数据库中查数据找到后返回了结果

第二次查询就直接从redis缓存中查到了数据 减少了数据库的压力 发挥出了redis的效果

Logo

更多推荐