前言
我们本博文主要讲解一下SpringCloud Alibaba的使用方法。通过Nacos + Sentinel + Dubbo的架构方式来搭建一个微服务架子。
Nacos搭建
参看博文:SpringCloud Alibaba之Nacos。
Sentinel Dashboard搭建
参看博文: SpringCloud Alibaba之Sentinel。
搭建父工程
我们创建一个Maven项目spring-cloud-demo,其pom结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--spring boot 父启动器依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<groupId>com.rubin</groupId>
<artifactId>spring-cloud-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>sca</module>
</modules>
<packaging>pom</packaging>
<dependencies>
<!--日志依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok⼯具-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<!-- Actuator可以帮助你监控和管理Spring Boot应用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!--SCA -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--SCA -->
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!--编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<!--打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在其下面创建子模块sca,其pom结构为:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-demo</artifactId>
<groupId>com.rubin</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>sca-service-common</module>
<module>sca-service-resume</module>
<module>sca-service-auto-deliver</module>
</modules>
<artifactId>sca</artifactId>
</project>
创建公用服务
在sca模块下创建公用模块sca-service-common,其pom结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sca</artifactId>
<groupId>com.rubin</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sca-service-common</artifactId>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
服务提供者
在sca模块下创建服务提供者模块sca-service-resume,其pom结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sca</artifactId>
<groupId>com.rubin</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sca-service-resume</artifactId>
<dependencies>
<!--spring cloud alibaba dubbo 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
</dependency>
<dependency>
<groupId>com.rubin</groupId>
<artifactId>sca-service-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
创建数据库spring_cloud_db,导入如下SQL:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for r_resume
-- ----------------------------
DROP TABLE IF EXISTS `r_resume`;
CREATE TABLE `r_resume` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sex` varchar(10) DEFAULT NULL COMMENT '性别',
`birthday` varchar(30) DEFAULT NULL COMMENT '出生日期',
`work_year` varchar(100) DEFAULT NULL COMMENT '工作年限',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号码',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`status` varchar(80) DEFAULT NULL COMMENT '目前状态',
`resume_name` varchar(500) DEFAULT NULL COMMENT '简历名称',
`name` varchar(40) DEFAULT NULL,
`create_time` datetime DEFAULT NULL COMMENT '创建日期',
`head_pic` varchar(100) DEFAULT NULL COMMENT '头像',
`is_del` int(2) DEFAULT NULL COMMENT '是否删除 默认值0-未删除 1-已删除',
`update_time` datetime DEFAULT NULL COMMENT '简历更新时间',
`user_id` int(11) DEFAULT NULL COMMENT '用户ID',
`is_default` int(2) DEFAULT NULL COMMENT '是否为默认简历 0-默认 1-非默认',
`highest_education` varchar(20) DEFAULT '' COMMENT '最高学历',
`deliver_near_by_confirm` int(2) DEFAULT '0' COMMENT '投递附件简历确认 0-需要确认 1-不需要确认',
`refuse_count` int(11) NOT NULL DEFAULT '0' COMMENT '简历被拒绝次数',
`mark_can_interview_count` int(11) NOT NULL DEFAULT '0' COMMENT '被标记为可面试次数',
`have_notice_inter_count` int(11) NOT NULL DEFAULT '0' COMMENT '已通知面试次数',
`one_word` varchar(100) DEFAULT '' COMMENT '一句话介绍自己',
`live_city` varchar(100) DEFAULT '' COMMENT '居住城市',
`resume_score` int(3) DEFAULT NULL COMMENT '简历得分',
`user_identity` int(1) DEFAULT '0' COMMENT '用户身份1-学生 2-工人',
`is_open_resume` int(1) DEFAULT '3' COMMENT '人才搜索-开放简历 0-关闭,1-打开,2-简历未达到投放标准被动关闭 3-从未设置过开放简历',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2195388 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of r_resume
-- ----------------------------
BEGIN;
INSERT INTO `r_resume` VALUES (2195320, '女', '1990', '2年', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿的简历', 'wps', '2015-04-24 13:40:14', 'images/myresume/default_headpic.png', 0, '2015-04-24 13:40:14', 1545132, 1, '本科', 0, 0, 0, 0, '', '广州', 15, 0, 3);
INSERT INTO `r_resume` VALUES (2195321, '女', '1990', '2年', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿的简历', 'wps', '2015-04-24 14:17:54', 'images/myresume/default_headpic.png', 0, '2015-04-24 14:20:35', 1545133, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195322, '女', '1990', '2年', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿的简历', 'wps', '2015-04-24 14:42:45', 'images/myresume/default_headpic.png', 0, '2015-04-24 14:43:34', 1545135, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195323, '女', '1990', '2年', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿的简历', 'wps', '2015-04-24 14:48:19', 'images/myresume/default_headpic.png', 0, '2015-04-24 14:50:34', 1545136, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195331, '女', '1990', '2年', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿的简历', 'wps', '2015-04-24 18:43:35', 'images/myresume/default_headpic.png', 0, '2015-04-24 18:44:08', 1545145, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195333, '女', '1990', '2年', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿的简历', 'wps', '2015-04-24 19:01:13', 'images/myresume/default_headpic.png', 0, '2015-04-24 19:01:14', 1545148, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195336, '女', '1990', '2年', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿的简历', 'wps', '2015-04-27 14:13:02', 'images/myresume/default_headpic.png', 0, '2015-04-27 14:13:02', 1545155, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195337, '女', '1990', '2年', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿的简历', 'wps', '2015-04-27 14:36:55', 'images/myresume/default_headpic.png', 0, '2015-04-27 14:36:55', 1545158, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195369, '女', '1990', '10年以上', '199999999', 'test@testtest01.com', '我目前已离职,可快速到岗', '稻壳儿', 'wps', '2015-05-15 18:08:19', 'images/myresume/default_headpic.png', 0, '2015-05-15 18:08:19', 1545346, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195374, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 17:53:37', 'images/myresume/default_headpic.png', 0, '2015-06-04 17:53:39', 1545523, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195375, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:11:06', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:11:07', 1545524, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195376, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:12:19', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:12:19', 1545525, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195377, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:13:28', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:13:28', 1545526, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195378, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:15:16', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:15:16', 1545527, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195379, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:23:06', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:23:06', 1545528, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195380, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:23:38', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:23:39', 1545529, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195381, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:27:33', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:27:33', 1545530, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195382, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:31:36', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:31:39', 1545531, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195383, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 18:36:48', 'images/myresume/default_headpic.png', 0, '2015-06-04 18:36:48', 1545532, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195384, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 19:15:15', 'images/myresume/default_headpic.png', 0, '2015-06-04 19:15:16', 1545533, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195385, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 19:28:53', 'images/myresume/default_headpic.png', 0, '2015-06-04 19:28:53', 1545534, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195386, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 19:46:42', 'images/myresume/default_headpic.png', 0, '2015-06-04 19:46:45', 1545535, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
INSERT INTO `r_resume` VALUES (2195387, '女', '1990', '1年', '199999999', 'test@testtest01.com', '我目前正在职,正考虑换个新环境', '稻壳儿', 'wps', '2015-06-04 19:48:16', 'images/myresume/default_headpic.png', 0, '2015-06-04 19:48:16', 1545536, 1, '本科', 0, 0, 0, 0, '', '广州', 65, 0, 3);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
创建配置文件bootstrap.yml如下:
spring:
application:
name: sca-service-resume
cloud:
nacos:
discovery:
# 配置nacos server地址
server-addr: nacos-host:8848
namespace: 651d1e6f-4bf4-46b9-b5b0-1885a215dc12
config:
server-addr: nacos-host:8848
namespace: 651d1e6f-4bf4-46b9-b5b0-1885a215dc12
prefix: sca-service-resume
group: DEFAULT_GROUP
file-extension: yaml
ext-config[0]:
data-id: actuator.yaml
group: DEFAULT_GROUP
refresh: true
在Nacos里面创建配置文件sca-service-resume.yaml:
server:
port: 9010
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/spring_cloud_db?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
main:
allow-bean-definition-overriding: true
dubbo:
scan:
# dubbo 服务扫描基准包
base-packages: com.rubin.sca.service.resume.service
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端口( -1 表示自增端口,从 20880 开始)
port: -1
registry:
# 挂载到 Spring Cloud 的注册中心
address: spring-cloud://localhost
创建actuator.yaml如下:
# springboot中暴露健康检查等断点接口
management:
endpoints:
web:
exposure:
include: "*"
# 暴露健康接口的细节
endpoint:
health:
show-details: always
创建启动类:
package com.rubin.sca.service.resume;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan(basePackages = "com.rubin.sca.service.resume.mapper")
public class ScaServiceResumeBootstrap {
public static void main(String[] args) {
SpringApplication.run(ScaServiceResumeBootstrap.class, args);
}
}
在sca-service-common里面创建公用实体和共用接口:
package com.rubin.sca.service.common.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
*
* </p>
*
* @author rubin
* @since 2021-09-29
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class RResume implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 性别
*/
private String sex;
/**
* 出生日期
*/
private String birthday;
/**
* 工作年限
*/
private String workYear;
/**
* 手机号码
*/
private String phone;
/**
* 邮箱
*/
private String email;
/**
* 目前状态
*/
private String status;
/**
* 简历名称
*/
private String resumeName;
private String name;
/**
* 创建日期
*/
private LocalDateTime createTime;
/**
* 头像
*/
private String headPic;
/**
* 是否删除 默认值0-未删除 1-已删除
*/
private Integer isDel;
/**
* 简历更新时间
*/
private LocalDateTime updateTime;
/**
* 用户ID
*/
private Integer userId;
/**
* 是否为默认简历 0-默认 1-非默认
*/
private Integer isDefault;
/**
* 最高学历
*/
private String highestEducation;
/**
* 投递附件简历确认 0-需要确认 1-不需要确认
*/
private Integer deliverNearByConfirm;
/**
* 简历被拒绝次数
*/
private Integer refuseCount;
/**
* 被标记为可面试次数
*/
private Integer markCanInterviewCount;
/**
* 已通知面试次数
*/
private Integer haveNoticeInterCount;
/**
* 一句话介绍自己
*/
private String oneWord;
/**
* 居住城市
*/
private String liveCity;
/**
* 简历得分
*/
private Integer resumeScore;
/**
* 用户身份1-学生 2-工人
*/
private Integer userIdentity;
/**
* 人才搜索-开放简历 0-关闭,1-打开,2-简历未达到投放标准被动关闭 3-从未设置过开放简历
*/
private Integer isOpenResume;
}
package com.rubin.sca.service.common.service;
import com.rubin.sca.service.common.entity.RResume;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author rubin
* @since 2021-09-29
*/
public interface IRResumeService {
String hello();
List<RResume> getResumes();
RResume getResumeDetail(Long userId);
String timeout() throws InterruptedException;
}
创建dao层:
package com.rubin.sca.service.resume.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.rubin.sca.service.common.entity.RResume;
/**
* <p>
* Mapper 接口
* </p>
*
* @author rubin
* @since 2021-09-29
*/
public interface RResumeMapper extends BaseMapper<RResume> {
}
<?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.rubin.sca.service.resume.mapper.RResumeMapper">
</mapper>
service层:
package com.rubin.sca.service.resume.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rubin.sca.service.common.entity.RResume;
import com.rubin.sca.service.common.service.IRResumeService;
import com.rubin.sca.service.resume.mapper.RResumeMapper;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Value;
import java.util.List;
import java.util.Random;
@Service
public class ResumeServiceImpl extends ServiceImpl<RResumeMapper, RResume> implements IRResumeService, IService<RResume> {
private static final Random random = new Random();
@Value("${server.port}")
private Integer port;
@Override
public String hello() {
return "Hello! This is from port : " + port;
}
@Override
public List<RResume> getResumes() {
return list();
}
@Override
public RResume getResumeDetail(Long userId) {
QueryWrapper<RResume> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId);
return getOne(queryWrapper);
}
@Override
public String timeout() throws InterruptedException {
Thread.sleep(random.nextInt(2000));
return hello();
}
}
controller层:
package com.rubin.sca.service.resume.controller;
import com.rubin.sca.service.common.entity.RResume;
import com.rubin.sca.service.common.service.IRResumeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author rubin
* @since 2021-09-29
*/
@RestController
@RequestMapping("/resume")
public class RResumeController {
@Autowired
private IRResumeService irResumeService;
@GetMapping("hello")
public String hello() {
return irResumeService.hello();
}
@GetMapping("list")
public List<RResume> getResumes() {
return irResumeService.getResumes();
}
@GetMapping("detail")
public RResume getResumeDetail(@RequestParam("userId") Long userId) {
return irResumeService.getResumeDetail(userId);
}
@GetMapping("timeout")
public String timeout() throws InterruptedException {
return irResumeService.timeout();
}
}
服务消费者
在sca模块下创建服务消费者模块sca-service-auto-deliver,其pom结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sca</artifactId>
<groupId>com.rubin</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sca-service-auto-deliver</artifactId>
<dependencies>
<dependency>
<groupId>com.rubin</groupId>
<artifactId>sca-service-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--spring cloud alibaba dubbo 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!--sentinel 核心环境依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel支持采用 Nacos 作为规则配置数据源,引⼊该适配依赖 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
</dependencies>
</project>
创建配置文件bootstrap.yml如下:
spring:
application:
name: sca-service-auto-deliver
cloud:
nacos:
discovery:
# 配置nacos server地址
server-addr: nacos-host:8848
namespace: 651d1e6f-4bf4-46b9-b5b0-1885a215dc12
config:
server-addr: nacos-host:8848
namespace: 651d1e6f-4bf4-46b9-b5b0-1885a215dc12
prefix: sca-service-auto-deliver
group: DEFAULT_GROUP
file-extension: yaml
ext-config[0]:
data-id: actuator.yaml
group: DEFAULT_GROUP
refresh: true
在Nacos里面创建对应的配置文件sca-service-auto-deliver.yaml:
server:
port: 9011
spring:
main:
allow-bean-definition-overriding: true
cloud:
sentinel:
transport:
# sentinel dashboard/console地址
dashboard: 127.0.0.1:8080
# sentinel会在该端口启动http server,那么这样的话,控制台定义的⼀些限流等规则才能发送传递过来
# 如果8719端口被占⽤,那么会依次+1
port: 8719
# Sentinel Nacos数据源配置,Nacos中的规则会⾃动同步到sentinel控制台的流控规则中
datasource:
# 此处的flow为⾃定义数据源名
# 流控规则
flow:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
namespace: 651d1e6f-4bf4-46b9-b5b0-1885a215dc12
data-id: ${spring.application.name}-flow-rules.json
groupId: DEFAULT_GROUP
data-type: json
# 类型来⾃RuleType类
rule-type: flow
degrade:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
namespace: 651d1e6f-4bf4-46b9-b5b0-1885a215dc12
data-id: ${spring.application.name}-degrade-rules.json
groupId: DEFAULT_GROUP
data-type: json
rule-type: degrade
dubbo:
registry:
# 挂载到 Spring Cloud 的注册中心
address: spring-cloud://localhost
cloud:
subscribed-services: sca-service-resume
创建启动类:
package com.rubin.autodeliver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ScaServiceAutoDeliverBootstrap {
public static void main(String[] args) {
SpringApplication.run(ScaServiceAutoDeliverBootstrap.class, args);
}
}
常见controller消费消费者接口并对外提供服务:
package com.rubin.autodeliver.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.rubin.autodeliver.fallback.SentinelFallbackClass;
import com.rubin.sca.service.common.entity.RResume;
import com.rubin.sca.service.common.service.IRResumeService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Random;
@RestController
@RequestMapping("auto-deliver")
public class AutoDeliverController {
private static final Random random = new Random();
@Reference
private IRResumeService irResumeService;
@GetMapping("resume/{userId}")
public RResume getResumeByUserId(@PathVariable("userId") Long userId) {
return irResumeService.getResumeDetail(userId);
}
@GetMapping("resumes")
public List getResumes() {
return irResumeService.getResumes();
}
@GetMapping("hello")
public String hello() {
return irResumeService.hello();
}
@GetMapping("timeout")
public String timeout() throws InterruptedException {
return irResumeService.timeout();
}
@GetMapping("sentinel")
@SentinelResource(value = "sentinel",
blockHandlerClass = SentinelFallbackClass.class,
blockHandler = "handleBlock",
fallbackClass = SentinelFallbackClass.class,
fallback = "handleException"
)
public String sentinel() {
if (random.nextBoolean()) {
int i = 3/0;
}
return irResumeService.hello();
}
}
创建熔断对应的兜底方法类:
package com.rubin.autodeliver.fallback;
import com.alibaba.csp.sentinel.slots.block.BlockException;
public class SentinelFallbackClass {
public static String handleBlock(BlockException blockException) {
blockException.printStackTrace();
return "被Sentinel限流了";
}
public static String handleException() {
return "调用失败了,直接熔断";
}
}
至此,我们最简单的SpringCloud Alibaba的使用案例就搭建完成了。欢迎小伙伴们积极留言交流~~~
文章评论