zoukankan      html  css  js  c++  java
  • 基于springboot+dubbo的简易分布式小Demo

     

      新手都能看懂!手把手教你使用SpringBoot+Dubbo搭建一个简单的分布式服务。


    文章内容

    此文使用springboot+dubbo+zookeeper+redis搭建一个简易的分布式服务。

    环境准备

    1、zookeeper环境安装;

    2、redis环境安装;

    3、mysql环境安装。

    实现的业务功能

    1、根据一定条件查询hero记录,并生成相应缓存;

    2、查询记录数,进行缓存,并设置有效期;

    3、新增hero记录,清空所有记录缓存,因为记录要求实时性;但不清空记录数缓存,这个不要求实时性。

    代码实现

    基础项目搭建

    新建maven项目dubbo-interface。定义公共内容。

    1、实体类:

     1 package com.zomi.bean;
     2  3 import java.io.Serializable;
     4 import java.util.Date;
     5  6 public class Hero implements Serializable{
     7     
     8     private static final long serialVersionUID = 1L;
     9     
    10     private int id ;
    11     private String name ;
    12     private String remark ;
    13     private int level ;
    14     private Date date ;
    15     //省去getter、setter、toString
    16 }
    View Code

    2、功能接口:

     1 package com.zomi.service;
     2  3 import java.util.List;
     4  5 import com.zomi.bean.Hero;
     6  7 public interface HeroService {
     8  9     void addHero(Hero hero);
    10     List<Hero> findHeros(int level);
    11     int findHerosCount();
    12 }
    View Code

    3、maven install 打包,供之后项目使用。

    提供者

    新建spring boot工程dubbo-provider

    1、添加pom依赖

     1 <dependency>
     2             <groupId>org.springframework.boot</groupId>
     3             <artifactId>spring-boot-starter-web</artifactId>
     4         </dependency>
     5         <!-- 引入公共接口项目 -->
     6         <dependency>
     7             <groupId>com.zomi</groupId>
     8             <artifactId>dubbo-interface</artifactId>
     9             <version>0.0.1-SNAPSHOT</version>
    10         </dependency>
    11         <!-- 引入dubbo的依赖 -->
    12         <dependency>
    13             <groupId>com.alibaba.spring.boot</groupId>
    14             <artifactId>dubbo-spring-boot-starter</artifactId>
    15             <version>2.0.0</version>
    16         </dependency>
    17         <!-- 引入zookeeper的依赖 -->
    18         <dependency>
    19             <groupId>com.101tec</groupId>
    20             <artifactId>zkclient</artifactId>
    21             <version>0.10</version>
    22         </dependency>
    23         <!-- slf4j依赖 -->
    24         <dependency>
    25             <groupId>org.slf4j</groupId>
    26             <artifactId>slf4j-log4j12</artifactId>
    27             <scope>test</scope>
    28         </dependency>
    29         <!-- 添加redis-springboot整合依赖 -->
    30         <dependency>
    31             <groupId>org.springframework.boot</groupId>
    32             <artifactId>spring-boot-starter-data-redis</artifactId>
    33         </dependency>
    34         <!-- 添加mybatis-springboot整合依赖 -->
    35         <dependency>
    36             <groupId>org.mybatis.spring.boot</groupId>
    37             <artifactId>mybatis-spring-boot-starter</artifactId>
    38             <version>1.3.2</version>
    39         </dependency>
    40         <!-- 添加mysql驱动依赖 -->
    41         <dependency>
    42             <groupId>mysql</groupId>
    43             <artifactId>mysql-connector-java</artifactId>
    44         </dependency>
    45         <!-- druid依赖 -->
    46         <dependency>
    47             <groupId>com.alibaba</groupId>
    48             <artifactId>druid</artifactId>
    49             <version>1.1.21</version>
    50         </dependency>
    View Code

    2、dao层

     1 package com.zomi.mapper;
     2  3 import java.util.List;
     4 import org.apache.ibatis.annotations.Mapper;
     5 import com.zomi.bean.Hero;
     6  7 @Mapper
     8 public interface HeroMapper {
     9     void insertHero(Hero hero);
    10     List<Hero> selectHerosByLevel(int level);
    11     int selectCount();
    12 }
    View Code
     1 <?xml version="1.0" encoding="UTF-8" ?>
     2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
     3 <mapper namespace="com.zomi.mapper.HeroMapper" >
     4     <insert id="insertHero">
     5         insert into Hero(name,remark,level,date) values(#{name},#{remark},#{level},#{date})
     6     </insert>
     7     <select id="selectHerosByLevel" resultType="hero">
     8         select id,name,remark,level,date from hero where level &lt;=#{hehelevel}
     9     </select>
    10     <select id="selectCount" resultType="int">
    11         select count(1) from hero
    12     </select>
    13 </mapper>
    View Code

    3、Service层

     1 package com.zomi.service.impl;
     2  3 import java.util.List;
     4 import java.util.concurrent.TimeUnit;
     5  6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.cache.annotation.CacheEvict;
     8 import org.springframework.cache.annotation.Cacheable;
     9 import org.springframework.data.redis.core.BoundValueOperations;
    10 import org.springframework.data.redis.core.RedisTemplate;
    11 import org.springframework.stereotype.Component;
    12 import org.springframework.transaction.annotation.Transactional;
    13 14 import com.alibaba.dubbo.config.annotation.Service;
    15 import com.zomi.bean.Hero;
    16 import com.zomi.mapper.HeroMapper;
    17 import com.zomi.service.HeroService;
    18 19 @Service //注意这个是dubbo里边的注解,而不是springframework里边的注解
    20 @Component
    21 public class HeroServiceImpl implements HeroService {
    22 23     @Autowired
    24     HeroMapper mapper ;
    25     @Autowired
    26     private RedisTemplate<Object, Object> redisTemplate ;
    27     
    28     @CacheEvict(value="realTimeCache", allEntries=true)
    29     @Transactional(rollbackFor=Exception.class) //事务控制
    30     @Override
    31     public void addHero(Hero hero) {
    32         mapper.insertHero(hero);
    33     }
    34 35     @Cacheable(value="realTimeCache", key="'hero_'+#level")
    36     @Override
    37     public List<Hero> findHeros(int level) {
    38         return mapper.selectHerosByLevel(level);
    39     }
    40 41     /**
    42      * redis高并发可能存在的三个问题:(此处针对热点缓存使用到了双重检测锁)
    43      * 1)缓存穿透:默认值
    44      * 2)缓存雪崩:提前规划
    45      * 3)热点缓存:双重检测锁
    46      */
    47     @Override
    48     public int findHerosCount() {
    49         //获取redis操作对象
    50         BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");
    51         //从缓存中读取数据
    52         Object count = ops.get();
    53         if(count == null) {
    54             synchronized(this) {
    55                 count = ops.get();
    56                 if(count == null) {
    57                     //如果缓存没有从db中读取数据
    58                     count = mapper.selectCount();
    59                     //将数据将入到缓存中
    60                     ops.set(count, 10, TimeUnit.SECONDS);
    61                 }
    62             }
    63         }
    64         return (int) count;
    65     }
    66 67 }
    View Code

    4、启动类

     1 package com.zomi;
     2  3 import org.springframework.boot.SpringApplication;
     4 import org.springframework.boot.autoconfigure.SpringBootApplication;
     5 import org.springframework.cache.annotation.EnableCaching;
     6 import org.springframework.transaction.annotation.EnableTransactionManagement;
     7  8 import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
     9 10 @EnableTransactionManagement //开启dubbo的事务管理,否则服务会注册不上
    11 @EnableDubboConfiguration //开启dubbo的自动配置
    12 @SpringBootApplication
    13 @EnableCaching //开启缓存功能
    14 public class DubboProviderApplication {
    15 16     public static void main(String[] args) {
    17         SpringApplication.run(DubboProviderApplication.class, args);
    18     }
    19 20 }
    View Code

    5、配置文件

     1 #配置端口、服务暴露名称
     2 server:
     3   port: 8000
     4  5 #配置服务暴露名称、dubbo注册中心地址
     6 spring:
     7   application:
     8     name: dubbo-provider
     9   dubbo:
    10     registry: zookeeper://zkOS:2181
    11 12 #配置数据源、redis缓存
    13   datasource:
    14     type: com.alibaba.druid.pool.DruidDataSource
    15     driver-class-name: com.mysql.jdbc.Driver
    16     url: jdbc:mysql://aliyun:3306/hero?characterEncoding=utf8
    17     username: root
    18     password: "这里填你的密码"
    19   mvc:
    20     date-format: yyyyMMdd
    21 22   redis:
    23     host: aliyun
    24     port: 6379
    25     password: "这里填你的密码"
    26 27   cache:
    28     type: redis
    29     cache-names: realTimeCache #缓存命名空间列表,可以执行多个
    30 31 #mybatis配置  
    32 mybatis:
    33   mapper-locations:
    34   - classpath:com/zomi/mapper/*.xml
    35   type-aliases-package: com.zomi.bean
    View Code

    6、添加上日志配置。通过日志可以监控到sql语句、同时可以判断是否使用了缓存。

      注意:此日志文件必须在resources路径下,与application.yml同级,且命名为logback.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <configuration>
     3      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
     4             <encoder>
     5                     <!-- %level %msg%n -->
     6                    <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
     7             </encoder>
     8     </appender>
     9    <root level="WARN">
    10         <appender-ref ref="STDOUT"/>
    11    </root>
    12    
    13    <logger name="com.zomi.mapper" level="DEBUG"></logger>
    14 </configuration>
    View Code

    消费者

    新建springboot工程dubbo-consumer

    1、添加pom依赖

     1 <dependency>
     2             <groupId>org.springframework.boot</groupId>
     3             <artifactId>spring-boot-starter-web</artifactId>
     4         </dependency>
     5         <!-- 引入公共接口项目 -->
     6         <dependency>
     7             <groupId>com.zomi</groupId>
     8             <artifactId>dubbo-interface</artifactId>
     9             <version>0.0.1-SNAPSHOT</version>
    10         </dependency>
    11         <!-- 引入dubbo的依赖 -->
    12         <dependency>
    13             <groupId>com.alibaba.spring.boot</groupId>
    14             <artifactId>dubbo-spring-boot-starter</artifactId>
    15             <version>2.0.0</version>
    16         </dependency>
    17         <!-- 引入zookeeper的依赖 -->
    18         <dependency>
    19             <groupId>com.101tec</groupId>
    20             <artifactId>zkclient</artifactId>
    21             <version>0.10</version>
    22         </dependency>
    23         <!-- slf4j依赖 -->
    24         <dependency>
    25             <groupId>org.slf4j</groupId>
    26             <artifactId>slf4j-log4j12</artifactId>
    27             <scope>test</scope>
    28         </dependency>
    View Code

    2、controller层

     1 package com.zomi.controller;
     2  3 import java.util.List;
     4  5 import org.springframework.stereotype.Controller;
     6 import org.springframework.ui.Model;
     7 import org.springframework.web.bind.annotation.PostMapping;
     8 import org.springframework.web.bind.annotation.RequestMapping;
     9 import org.springframework.web.bind.annotation.ResponseBody;
    10 11 import com.alibaba.dubbo.config.annotation.Reference;
    12 import com.zomi.bean.Hero;
    13 import com.zomi.service.HeroService;
    14 15 @Controller
    16 public class HeroController {
    17     
    18     @Reference(check=false)
    19     HeroService service;
    20     
    21     @PostMapping("hero")
    22     public String addHero(Hero hero,Model model) {
    23         model.addAttribute("hero", hero);
    24         service.addHero(hero);
    25         return "/WEB-INF/welcome.jsp";
    26     }
    27     
    28     @RequestMapping("findHeros")
    29     public @ResponseBody List<Hero> findHeros(int level){
    30         return service.findHeros(level);
    31     }
    32     
    33     @RequestMapping("findHerosCount")
    34     public @ResponseBody int findHerosCount() {
    35         return service.findHerosCount();
    36     }
    37     
    38 }
    View Code

    3、启动类

    1 @EnableDubboConfiguration
    2 @SpringBootApplication
    3 public class DubboConsumerApplication {
    4 5     public static void main(String[] args) {
    6         SpringApplication.run(DubboConsumerApplication.class, args);
    7     }
    8 9 }
    View Code

    4、jsp页面

     1 <%@ page language="java" contentType="text/html; charset=UTF-8"
     2     pageEncoding="UTF-8"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     7 <title>英雄注册</title>
     8 </head>
     9 <body>
    10     注册成功!<br>
    11     ${hero}
    12 </body>
    13 </html>
    View Code
     1 <%@ page language="java" contentType="text/html; charset=UTF-8"
     2     pageEncoding="UTF-8"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     7 <title>英雄注册</title>
     8 </head>
     9 <body>
    10     <form action="hero" method="post">
    11         英雄名:<input type="text" name="name"><br>
    12         定位:<input type="text" name="remark"><br>
    13         熟练度:<input type="text" name="level"><br>
    14         日期:<input type="text" name="date"><br>
    15         <input type="submit" value="战斗">
    16     </form>
    17     <hr>
    18     <form action="findHeros" method="post">
    19         熟练度:<input type="text" name="level"><br>
    20         <input type="submit" value="查询">
    21     </form>
    22     <hr>
    23     <a href="findHerosCount">预估英雄数量</a>
    24 </body>
    25 </html>
    View Code

    5、配置文件

     1 #配置端口、服务暴露名称
     2 server:
     3   port: 8888
     4 #服务暴露名称
     5 spring:
     6   application:
     7     name: dubbo-consumer
     8 #配置dubbo注册中心地址
     9   dubbo:
    10     registry: zookeeper://zkOS:2181
    11
    View Code

    启动测试

    测试截图省略

    测试要点:

    ①服务注册是否成功

    ②服务发现、调用是否成功

    ③缓存是否生效

    ④缓存有效期是否生效

    ⑤新增记录是否清除缓存

     

    "我们所要追求的,永远不是绝对的正确,而是比过去的自己更好"
  • 相关阅读:
    第零次作业
    第一本书的学习笔记
    第一次作业
    第零次作业
    第一周作业
    第零次作业回复
    第零次作业
    第一周作业
    第0次作业
    第一次作业
  • 原文地址:https://www.cnblogs.com/zomicc/p/12533953.html
Copyright © 2011-2022 走看看