天天看点

Spring Boot中使用Dubbo

高并发下Redis会出现的问题:

  • 缓存穿透
  • 缓存雪崩
  • 热点缓存

一、定义commons工程11-dubboCommons

(1) 创建工程

创建Maven的Java工程,并命名为11-dubboCommons

(2) 定义pom文件

<groupId>com.abc</groupId>
<artifactId>11-dubboCommons</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<maven.compiler.source>1.8</maven.compiler.source>
	<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<version>1.18.4</version>
		<scope>provided</scope>
	</dependency>
</dependencies>
           

(3) 定义实体类

Spring Boot中使用Dubbo

(4) 定义业务接口

Spring Boot中使用Dubbo

(5) 将工程安装到本地库

运行Maven的install命令,将工程安装到本地版本库,以备其它工程使用

二、定义提供者11-provider-springboot

(1) 创建工程

创建一个Spring Boot工程,并重命名为11-provider-springboot

(2) 定义pom文件

A、添加dubbo与spring boot整合依赖

B、添加zkClient依赖

C、其它依赖

  • dubboCommons依赖
  • spring boot与redis整合依赖
  • mybatis与spring boot整合依赖
  • 数据源Druid依赖
  • mysql驱动依赖
  • slf4j-log4j12依赖
  • spring-boot-starter-web依赖
<groupId>com.abc</groupId>
    <artifactId>11-provider-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--dubbo与spring boot整合依赖-->
        <dependency>
            <groupId>com.alibaba.spring.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <!-- zk客户端依赖:zkclient -->
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.10</version>
        </dependency>
        <dependency>
            <groupId>com.abc</groupId>
            <artifactId>11-dubboCommons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--Spring Boot与Redis整合依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--mybatis与Spring Boot整合依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--数据源Druid依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--MySQL驱动依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>

        <resources>
            <!--注册dao包下mybatis映射文件为资源目录-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
           

(3) 定义Service实现类

import com.abc.bean.Employee;
import com.abc.dao.EmployeeDao;
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

@Service   // Dubbo的注解  <dubbo:service/>
@Component
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired
    private EmployeeDao dao;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    // 当有对象插入时会清空realTimeCache缓存空间
    @CacheEvict(value="realTimeCache", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addEmployee(Employee employee) {
        dao.insertEmployee(employee);
    }

    // 一旦有了查询结果,则会将此结果写入到realTimeCache缓存
    // key是employee_加上方法参数
    @Cacheable(value = {"realTimeCache"}, key = "'employee_'+#id")
    @Override
    public Employee findEmployeeById(int id) {
        // 从DB查询
        System.out.println("从DB查询id = " + id);
        return dao.selectEmployeeById(id);
    }

    private volatile Object count;
    // 双重检测锁机制解决Reids的热点缓存问题
    @Override
    public Integer findEmployeeCount() {
        // 获取Redis操作对象
        BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");
        // 从缓存获取数据
        count = ops.get();
        if(count == null) {
           synchronized (this) {
                count = ops.get();
                if(count == null) {
                    System.out.println("从DB中查询");
                    // 从DB中查询
                    count = dao.selectEmployeeCount();
                    // 将查询结果存放到Redis
                    ops.set(count, 10, TimeUnit.SECONDS);
                }
            }
        }
        return (Integer) count;
    }
}
           

(4) 定义Dao接口

Spring Boot中使用Dubbo

(5) 定义映射文件

Spring Boot中使用Dubbo

(6) 修改启动类

在启动类上必须要添加@EnableDubboConfiguration注解,开启Dubbo的自动配置功能

Spring Boot中使用Dubbo

(7) 修改主配置文件

server:
  port: 8888

mybatis:
  # 注册mybatis中实体类的别名
  type-aliases-package: com.abc.bean
  # 注册映射文件
  mapper-locations: classpath:com/abc/dao/*.xml

spring:
  # 注册数据源
  datasource:
    # 指定数据源类型为Druid
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///test?useUnicode=true&amp;characterEncoding=utf8
    username: root
    password: root

  # 连接Redis服务器
  redis:
    host: 39.97.176.160
    port: 6379

  # 连接Redis高可有集群
  #  redis:
  #    sentinel:
  #      master: mymaster
  #      nodes:
  #        - sentinelOS1:26379
  #        - sentinelOS2:26379
  #        - sentinelOS3:26379

  # 配置缓存
  cache:
    type: redis # 指定缓存类型
    cache-names: realTimeCache  # 指定缓存区域名称


  # 功能等价于spring-boot配置文件中的<dubbo:application/>
  application:
    name: 11-provider-springboot
  # 指定zk注册中心
  dubbo:
    registry: zookeeper://39.97.176.160:2181
  # zk集群作注册中心
  # registry: zookeeper://zkOS1:2181?backup=zkOS2:2181,zkOS3:2181
           

三、定义消费者11-consumer-springboot

(1) 创建工程

创建一个Spring Boot工程,并重命名为11-consumer-springboot

(2) 定义pom文件

  • dubbo与spring boot整合依赖
  • zkClient依赖
  • dubboCommons依赖
  • JSP引擎jasper依赖
  • slf4j-log4j12依赖
  • spring-boot-starter-web依赖

(3) 修改主配置文件

spring:
  # 功能等价于spring-dubbo配置文件中的<dubbo:application/>
  application:
    name: 11-consumer-springboot
  # 指定zk注册中心
  dubbo:
    registry: zookeeper://39.97.176.160:2181
    # zk集群作注册中心
    # registry: zookeeper://zkOS1:2181?backup=zkOS2:2181,zkOS3:2181
           

(4) 创建index.jsp页面

在src/main/webapp目录下定义index.jsp文件

Spring Boot中使用Dubbo

(5) 定义处理器

package com.abc.controller;

import com.abc.bean.Employee;
import com.abc.service.EmployeeService;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/consumer/employee")
public class SomeController {

    // @Autowired
    @Reference   // Dubbo的注解   <dubbo:reference />
    private EmployeeService employeeService;

    @PostMapping("/register")
    public String someHandle(Employee employee, Model model) {
        employeeService.addEmployee(employee);
        model.addAttribute("employee", employee);
        return "/welcome.jsp";
    }

    @RequestMapping("/find/{id}")
    @ResponseBody
    public Employee findHandle(@PathVariable("id") int id) {
        return employeeService.findEmployeeById(id);
    }

    @RequestMapping("/count")
    @ResponseBody
    public Integer countHandle() {
        return employeeService.findEmployeeCount();
    }

}
           

(6) 定义welcome.jsp页面

Spring Boot中使用Dubbo

(7) 修改入口类

Spring Boot中使用Dubbo

四、测试

当有对象插入时会清空realTimeCache缓存空间

一旦有了查询结果,则会将此结果写入到realTimeCache缓存

http://localhost:8080/index.jsp  首页

http://localhost:8080//consumer/employee/find/2 根据Id查找

http://localhost:8080//consumer/employee/count 查找总数

继续阅读