- Provider:暴露服务的服务提供方
- Consumer:调用远程服务的服务消费方
- Registry:提供注册与调用服务的注册中心
- Monitor:统计服务的调用次数和调用时间的监控中心
- Container:服务运行容器,例如spring容器
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心Monitor。
- Zookeeper:Dubbo建议使用Zookeeper作为服务的注册中心
- redis(window版)
- redis-desktop-manager:redis的可视化管理,相当于sqlyog
- dubbo-war:可视化监控中心
- postpan:用于做接口请求测试,无论是前端,后台还是测试人员,都可以用 postman 来测试接口,用起来非常方便。
- student_info: 用到的数据库
——————————————————开始搭建————————————————————
3. 创建通用项目——common 3-1.用maven创建: 3-2.所需的依赖:也是提供者与消费所需的模块3-2.创建实体类:pojojunit junit4.11 test log4j log4j1.2.17
编写通用的实体类,用于给其他项目模块使用
Student类:
package cn.common.pojo;
import java.io.Serializable;
import java.util.Date;
public class Student implements Serializable {
private static final long serialVersionUID = 212298760094457193L;
private Integer id;
private String sname;
private Date birthday;
private String gender;
private String telephone;
private String email;
private Integer classid;
private String cname;
//get已set方法已省略
}
Classes 类:
package cn.common.pojo;
import java.io.Serializable;
public class Classes implements Serializable {
private static final long serialVersionUID = -39827967746559332L;
private Integer id;
private String cname;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
}
3-3.RPC接口
这是一个通用的接口,用于给其他模块和项目调用,也是通用项目中的service
CommonStudentService:
package cn.common.service;
import cn.common.pojo.Student;
import java.util.List;
public interface CommonStudentService {
List findAllStudeng();
}
到这里路通用项目已经简单搭建完成,实际项目中还有很多,根据业务需求进行编写
3-4.最后使用maven将通用项目打成jar包,在其他项目中进行引入依赖所在的路径:
打成jar包后的依赖坐标就是通用项目的pom.xml
org.example student_common1.0-SNAPSHOT
4.创建提供者——Provider 4-1.使用idea创建springboot项目——版本2.0.0.RELEASE 4-2.导入依赖
org.springframework.boot
spring-boot-starter-data-redis
com.alibaba
fastjson
1.2.75
com.alibaba.spring.boot
dubbo-spring-boot-starter
2.0.0
com.101tec
zkclient
0.10
org.example
student_common
1.0-SNAPSHOT
org.junit.jupiter
junit-jupiter-api
test
4-3.配置文件application.properties
#端口号,可以直接在这里进行修改
server.port=8081
#配置连接数据库的相关参数
spring.datasource.url=jdbc:mysql://localhost:3306/student_info?characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#配置mybatis的映射文件的位置
mybatis.mapper-locations=classpath:mapper
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value.toString());
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value.toString(), time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long getExpireTime(String key){
long time = redisTemplate.getExpire(key);
return time;
}
public String getValue(String key) {
String result = null;
try {
ValueOperations valueOps = redisTemplate.opsForValue();
result = valueOps.get(key);
log.info("[REDIS] Get k-v key={}, value={}", key, result);
} catch (Exception e) {
log.error("[REDIS--ERROR]-->getValue(String key)错误:{}", e);
}
return result;
}
public Map multiGetValue(List keys) {
Map results = null;
try {
ValueOperations valueOps = redisTemplate.opsForValue();
List values = valueOps.multiGet(keys);
results = new HashMap<>(16);
if (!CollectionUtils.isEmpty(values) && !keys.isEmpty()) {
for (int i = 0; i < keys.size(); i++) {
String fieldName = keys.get(i);
String fieldValue = values.get(i);
// 如果对应的字段为null,则不需要放入
if (!StringUtils.isEmpty(fieldValue)) {
results.put(fieldName, fieldValue);
}
}
}
log.info("[REDIS] Get Map map=%s", results);
} catch (Exception e) {
log.error("[REDIS--ERROR] Get Map map=%s", results);
}
return results;
}
public void delete(Collection keys) {
try {
redisTemplate.delete(keys);
log.info("[REDIS] Delete keys=%s", keys);
} catch (Exception e) {
log.error("[REDIS] Delete keys=%s", keys);
}
}
public void delete(String key) {
try {
redisTemplate.delete(key);
log.info("[REDIS] Delete key=%s", key);
} catch (Exception e) {
log.error("[REDIS] Delete key=%s", key);
}
}
public List getList(String key, long start, long end){
List result = null;
try {
ListOperations opsForList = redisTemplate.opsForList();
result = opsForList.range(key, start, end);
log.info("[REDIS] getList list key=%s,result=%s", key, result);
} catch (Exception e) {
log.error("[REDIS] getList list key=%s,result=%s", key, result);
}
return result;
}
public void leftPushList(String key, List list) {
try {
ListOperations opsForList = redisTemplate.opsForList();
opsForList.leftPushAll(key ,list);
log.info("[REDIS] leftPush list key=%s,value=%s", key, list);
} catch (Exception e) {
log.error("[REDIS] leftPush list key=%s,value=%s", key, list);
}
}
public T getJson(String key, Class entityClass) {
try {
String value = getValue(key);
if (StringUtils.isEmpty(value)) {
return null;
}
return JSON.parseObject(value, entityClass);
} catch (Exception e) {
log.error("从redis获取json对象失败:%s,异常信息为: %s", key, e.getMessage());
}
return null;
}
}
---StudentProviderService类:实现的是通用项目common中的service接口
注意:
这里的@Service是com.alibaba.dubbo.config.annotation里面的
所以还需要加@Component用于给spring管理
package cn.example.provider.service;
import cn.common.pojo.Student;
import cn.common.service.CommonStudentService;
import cn.example.provider.mapper.StudentProviderMapper;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.List;
@Component
@Service(interfaceClass = CommonStudentService.class)
public class StudentProviderService implements CommonStudentService {
@Autowired
private StudentProviderMapper spm;
@Autowired
private RedisService rs;
@Override
public List findAllStudeng() {
List studentList = null;
//先去redis中获取数据
String studentInfo = rs.getValue("student_info");
//判断redis是否有缓存数据
if (StringUtils.isEmpty(studentInfo)||studentInfo.equals("null")){
//如果没有缓存数据,就去mysql数据库中查询,并存入redis中
studentList = spm.getAllStudent();
//转json格式存入redis
String jsonString = JSON.toJSonString(studentList);
rs.set("student_info",jsonString,-1);
}else {
//如果有就直接取出
String jsonString = rs.getValue("student_info");
studentList = JSONObject.parseArray(jsonString,Student.class);
}
return studentList;
}
}
4-7.在启动类上添加@EnableDubboConfiguration注解
在com.alibaba.dubbo.spring.boot.annotation包下,开启dubbo框架
4-8.启动zookeepr如图(提供的安装包中有使用说明)
4-9.启动provider项目,看是否能够正常启动成功,并在zookeeper中开放服务接口
如果服务项目能够正常启动,并且在zookeeper中也有变化,说明应该是没问题的:
5.创建消费者——Consumer 5-1.使用idea创建springboot项目
创建时只需要添加web依赖
5-2.添加外部依赖坐标统一springboot的版本:2.0.0.RELEASE
com.alibaba.spring.boot
dubbo-spring-boot-starter
2.0.0
com.101tec
zkclient
0.10
org.example
student_common
1.0-SNAPSHOT
org.junit.jupiter
junit-jupiter-api
test
5-3.编写配置文件
#端口号,可以直接在这里进行修改 server.port=8082 #配置注册地址 #当前服务者的名字 spring.application.name=student_consumer #zookeeper注册地址 spring.dubbo.registry=zookeeper://127.0.0.1:2181 #注册协议 spring.dubbo.protocol=dubbo #不需要开放端口号,因为消费者是用来调提供者的 #spring.dubbo.port=20803 #第一个设置就是使用24小时的时间格式;第二个设置就是设置时区为东八区 spring.jackson.default-property-inclusion=NON_NULL spring.jackson.time-zone=GMT+8 #设置日期格式 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss5-4.编写service接口
这里的service接口与common中的service接口内容相同,但它只起到规范的作用,而在下面的service实现类中调用的依然是通用common项目中的service,然后common中的service调用的是提供者中provider的service实现类
package cn.example.consumer.service;
import cn.common.pojo.Student;
import java.util.List;
public interface StudentConsumerService {
List findAllStudent();
}
5-5.编写service的实现类
这里service实现类中调用的依然是通用common项目中的service接口,然后common中的service接口引用的是提供者中provider的service实现类,所以最终运行的是在provider中的业务
package cn.example.consumer.service.impl;
import cn.common.pojo.Student;
import cn.common.service.CommonStudentService;
import cn.example.consumer.service.StudentConsumerService;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentConsumerServiceImpl implements StudentConsumerService {
@Reference //引用common中提供的service接口
private CommonStudentService commonStudentService;
@Override
public List findAllStudent() {
return commonStudentService.findAllStudeng();
}
}
5-6.编写controller
package cn.example.consumer.controller;
import cn.common.pojo.Student;
import cn.example.consumer.service.StudentConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class StudentController {
@Autowired
private StudentConsumerService scs;
//查询所有学生信息
@RequestMapping("/findAllStudent")
public List findAllStudent(){
return scs.findAllStudent();
}
}
5-7.在启动类上添加@EnableDubboConfiguration注解
在com.alibaba.dubbo.spring.boot.annotation包下,开启dubbo框架
5-8.启动当前项目Consumer
- 前提是先启动provider和zookeeper
- 安装好提供的postman,打开进行测试
接着打开redis-desktop-manager查看redis中是否存入数据:
- db15是我们在provider项目中的配置文件配置 Redis配置 #数据库索引 0-15中设置的是15
- 这里的key是我们自己定义,实际开发中会有具体的规范
到这里说明我们基于springboot+dubbo+zookeeper+redis搭建的微服架构是没问题的,这也是最基础比较简单的



