基于springboot+dubbo的简易分布式小Demo

 

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


文章内容

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

环境准备

1、zookeeper环境安装;

2、redis环境安装;

3、mysql环境安装。

实现的业务功能

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

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

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

代码实现

一、基础项目搭建

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

1、实体类:

package com.zomi.bean;

import java.io.Serializable;
import java.util.Date;

public class Hero implements Serializable{

private static final long serialVersionUID = 1L;

private int id ;
private String name ;
private String remark ;
private int level ;
private Date date ;
//省去getter、setter、toString
}

2、功能接口:

package com.zomi.service;

import java.util.List;

import com.zomi.bean.Hero;

public interface HeroService {

void addHero(Hero hero);
List<Hero> findHeros(int level);
int findHerosCount();
}

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

二、提供者

新建spring boot工程dubbo-provider

1、添加pom依赖

<dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
<!-- 引入公共接口项目 -->
<dependency>
           <groupId>com.zomi</groupId>
           <artifactId>dubbo-interface</artifactId>
           <version>0.0.1-SNAPSHOT</version>
       </dependency>
       <!-- 引入dubbo的依赖 -->
       <dependency>
           <groupId>com.alibaba.spring.boot</groupId>
           <artifactId>dubbo-spring-boot-starter</artifactId>
           <version>2.0.0</version>
       </dependency>
       <!-- 引入zookeeper的依赖 -->
       <dependency>
           <groupId>com.101tec</groupId>
           <artifactId>zkclient</artifactId>
           <version>0.10</version>
       </dependency>
       <!-- slf4j依赖 -->
       <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-log4j12</artifactId>
           <scope>test</scope>
       </dependency>
       <!-- 添加redis-springboot整合依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 添加mybatis-springboot整合依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 添加mysql驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>

2、dao层

package com.zomi.mapper;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.zomi.bean.Hero;

@Mapper
public interface HeroMapper {
void insertHero(Hero hero);
List<Hero> selectHerosByLevel(int level);
int selectCount();
}
<?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" >
<mapper namespace="com.zomi.mapper.HeroMapper" >
<insert id="insertHero">
insert into Hero(name,remark,level,date) values(#{name},#{remark},#{level},#{date})
</insert>
<select id="selectHerosByLevel" resultType="hero">
select id,name,remark,level,date from hero where level &lt;=#{hehelevel}
</select>
<select id="selectCount" resultType="int">
select count(1) from hero
</select>
</mapper>

3、Service层

package com.zomi.service.impl;

import java.util.List;
import java.util.concurrent.TimeUnit;

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 com.alibaba.dubbo.config.annotation.Service;
import com.zomi.bean.Hero;
import com.zomi.mapper.HeroMapper;
import com.zomi.service.HeroService;

@Service //注意这个是dubbo里边的注解,而不是springframework里边的注解
@Component
public class HeroServiceImpl implements HeroService {

@Autowired
HeroMapper mapper ;
@Autowired
private RedisTemplate<Object, Object> redisTemplate ;

@CacheEvict(value="realTimeCache", allEntries=true)
@Transactional(rollbackFor=Exception.class) //事务控制
@Override
public void addHero(Hero hero) {
mapper.insertHero(hero);
}

@Cacheable(value="realTimeCache", key="'hero_'+#level")
@Override
public List<Hero> findHeros(int level) {
return mapper.selectHerosByLevel(level);
}

/**
* redis高并发可能存在的三个问题:(此处针对热点缓存使用到了双重检测锁)
* 1)缓存穿透:默认值
* 2)缓存雪崩:提前规划
* 3)热点缓存:双重检测锁
*/
@Override
public int findHerosCount() {
//获取redis操作对象
BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count");
//从缓存中读取数据
Object count = ops.get();
if(count == null) {
synchronized(this) {
count = ops.get();
if(count == null) {
//如果缓存没有从db中读取数据
count = mapper.selectCount();
//将数据将入到缓存中
ops.set(count, 10, TimeUnit.SECONDS);
}
}
}
return (int) count;
}

}

4、启动类

package com.zomi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;

@EnableTransactionManagement //开启dubbo的事务管理,否则服务会注册不上
@EnableDubboConfiguration //开启dubbo的自动配置
@SpringBootApplication
@EnableCaching //开启缓存功能
public class DubboProviderApplication {

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

}

5、配置文件

#配置端口、服务暴露名称
server:
port: 8000

#配置服务暴露名称、dubbo注册中心地址
spring:
application:
  name: dubbo-provider
dubbo:
  registry: zookeeper://zkOS:2181

#配置数据源、redis缓存
datasource:
  type: com.alibaba.druid.pool.DruidDataSource
  driver-class-name: com.mysql.jdbc.Driver
  url: jdbc:mysql://aliyun:3306/hero?characterEncoding=utf8
  username: root
  password: "这里填你的密码"
mvc:
  date-format: yyyyMMdd

redis:
  host: aliyun
  port: 6379
  password: "这里填你的密码"

cache:
  type: redis
  cache-names: realTimeCache #缓存命名空间列表,可以执行多个

#mybatis配置  
mybatis:
mapper-locations:
- classpath:com/zomi/mapper/*.xml
type-aliases-package: com.zomi.bean

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

此日志文件必须在resources路径下,与application.yml一样。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
           <encoder>
          <!-- %level %msg%n -->
                  <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
           </encoder>
   </appender>
  <root level="WARN">
       <appender-ref ref="STDOUT"/>
  </root>
 
  <logger name="com.zomi.mapper" level="DEBUG"></logger>
</configuration>

三、消费者

新建springboot工程dubbo-consumer

1、添加pom依赖

<dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
<!-- 引入公共接口项目 -->
<dependency>
           <groupId>com.zomi</groupId>
           <artifactId>dubbo-interface</artifactId>
           <version>0.0.1-SNAPSHOT</version>
       </dependency>
       <!-- 引入dubbo的依赖 -->
       <dependency>
           <groupId>com.alibaba.spring.boot</groupId>
           <artifactId>dubbo-spring-boot-starter</artifactId>
           <version>2.0.0</version>
       </dependency>
       <!-- 引入zookeeper的依赖 -->
       <dependency>
           <groupId>com.101tec</groupId>
           <artifactId>zkclient</artifactId>
           <version>0.10</version>
       </dependency>
       <!-- slf4j依赖 -->
       <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-log4j12</artifactId>
           <scope>test</scope>
       </dependency>

2、controller层

package com.zomi.controller;

import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.dubbo.config.annotation.Reference;
import com.zomi.bean.Hero;
import com.zomi.service.HeroService;

@Controller
public class HeroController {

@Reference(check=false)
HeroService service;

@PostMapping("hero")
public String addHero(Hero hero,Model model) {
model.addAttribute("hero", hero);
service.addHero(hero);
return "/WEB-INF/welcome.jsp";
}

@RequestMapping("findHeros")
public @ResponseBody List<Hero> findHeros(int level){
return service.findHeros(level);
}

@RequestMapping("findHerosCount")
public @ResponseBody int findHerosCount() {
return service.findHerosCount();
}

}

2、启动类

@EnableDubboConfiguration
@SpringBootApplication
public class DubboConsumerApplication {

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

}

3、jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
   pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>英雄注册</title>
</head>
<body>
注册成功!<br>
${hero}
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
   pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>英雄注册</title>
</head>
<body>
<form action="hero" method="post">
英雄名:<input type="text" name="name"><br>
定位:<input type="text" name="remark"><br>
熟练度:<input type="text" name="level"><br>
日期:<input type="text" name="date"><br>
<input type="submit" value="战斗">
</form>
<hr>
<form action="findHeros" method="post">
熟练度:<input type="text" name="level"><br>
<input type="submit" value="查询">
</form>
<hr>
<a href="findHerosCount">预估英雄数量</a>
</body>
</html>

4、配置文件

#配置端口、服务暴露名称
server:
port: 8888
#服务暴露名称
spring:
application:
  name: dubbo-consumer
#配置dubbo注册中心地址
dubbo:
  registry: zookeeper://zkOS:2181

四、启动测试

测试截图省略

测试要点:

①服务注册是否成功

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

③缓存是否生效

④缓存有效期是否生效

⑤新增记录是否清除缓存

 

猜你喜欢

转载自www.cnblogs.com/zomicc/p/12533953.html