SpringCloud-熔断器Hystrix
项目结构
父工程(每一个服务都是一个子工程)
-
pom.xml
<?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> <groupId>com.xiaoge.demo</groupId> <artifactId>hystrix-demo</artifactId> <version>1.0-SNAPSHOT</version> <modules> <module>user-service</module> <module>consumer-demo</module> <module>eureka-server</module> </modules> <packaging>pom</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.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> <spring-cloud.version>Finchley.SR1</spring-cloud.version> <mapper.starter.version>2.0.3</mapper.starter.version> <mysql.version>5.1.32</mysql.version> </properties> <dependencyManagement> <!-- 所有子工程, 必须引下面的依赖才会有 --> <dependencies> <!-- spring cloud 引用了它, 以后cloud依赖版本就不用写了 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 通用Mapper启动器 --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>${mapper.starter.version}</version> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- 因为不会再dependencyManagement标签里, 所以所有的子工程都可以用 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
consumer-demo服务
-
配置文件
-
pom.xml
<?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>hystrix-demo</artifactId> <groupId>com.xiaoge.demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>consumer-demo</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 引入eureka客户端依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- 引入负载均衡 ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <!-- 导入hystrix依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> </dependencies> </project>
-
application.yml
server: port: 8088 spring: # 在eureka中注册的服务名称 application: name: consumer-service # 注册方 # eureka配置 因为它要去注册中心注册, 所以要配置 eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka, http://127.0.0.1:10087/eureka # 配置所有的eureka地址, 防止其中一个eureka挂掉 registry-fetch-interval-seconds: 3 # 设置拉取服务列表的周期 为3秒 fetch-registry: true # 默认为true 拉取列表, 改为false 不拉取 instance: prefer-ip-address: true # 我希望使用ip地址 ip-address: 127.0.0.1 # 设置ip地址 # 对那个服务实现负载均衡 user-service: # 对user-service服务 (服务名称) ribbon: # 固定写法 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 使用负载均衡随机算法, 默认是轮询 # 设置hystrix的默认指令 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 3000 # 设置全局方法 的 超时 时间 为 3秒 超过 3秒 执行错误方法 # user-service: # 只针对一个的时候 (这里写服务名称 或者 方法名称) # execution: # isolation: # thread: # timeoutInMilliseconds: 3000 # 设置全局方法 的 超时 时间 为 3秒 超过 3秒 执行错误方法
-
-
启动类
-
ConsumerApplication
package com.xiaoge; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; /** * @program: cloud-demo * @description: 服务调用方 * @author: Mr.Xiao * @create: 2020-05-04 16:04 **/ // @EnableCircuitBreaker // hystrix注解 // @EnableDiscoveryClient // 它也是客户端, 它捷能兼容eureka 又能consul、zookeeper等等, 更通用, 更广泛 // @SpringBootApplication @SpringCloudApplication // 它的功能就是上面三个注解的功能 public class ConsumerApplication { @Bean @LoadBalanced // 加上ribbon 负载均衡注解 public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class); } }
-
-
实体类
-
User
package com.xiaoge.Consumer.pojo; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * @program: cloud-demo * @description: * @author: Mr.Xiao * @create: 2020-05-04 16:06 **/ @Data public class User implements Serializable { // 主键 private Long id; // 用户名 private String username; // 密码 private String password; // 姓名 private String name; // 年龄 private Integer age; // 性别,1男性,2女性 private Integer sex; // 出生日期 private Date birthday; // 创建时间 private Date created; // 更新时间 private Date updated; // 备注 private String note; }
-
-
表现层
-
ConsumerController
package com.xiaoge.Consumer.controller; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.xiaoge.Consumer.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; 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 org.springframework.web.client.RestTemplate; import java.util.List; /** * @program: cloud-demo * @description: 动态拉取服务列表 * @author: Mr.Xiao * @create: 2020-05-04 16:08 **/ @RestController @RequestMapping("/consumer") @DefaultProperties(defaultFallback = "defaultFallback") // 针对这个类下面的所有方法 public class ConsumerController { @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; // 专门负责服务发现 //@Autowired //private RibbonLoadBalancerClient client; // 专门负责 负载均衡 获取服务的 /* @GetMapping("/{id}") public User queryById(@PathVariable("id") Long id){ // 负载均衡算法: 随机, 轮询. hash // 1. 在注册restTemplate上加注解@LoadBalanced // 2. 直接写路径 String url = "http://user-service/user/" + id; User user = restTemplate.getForObject(url, User.class); return user; } */ @GetMapping("/{id}") /* @HystrixCommand(fallbackMethod = "queryByIdFallback") // 开启服务的线程隔离 和 降级处理 和指定错误方法 (只是针对这个方法) @HystrixCommand(commandProperties = { HystrixCommand 开启线程隔离 和 降级处理 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") // 设置超时时长3秒, 3秒没有响应, 执行错误方法 }) 类上面配置了错误方法, 我这里只需要 开启线程隔离 和 降级处理 和 给这个方法设置超时时长 想要整体配置只能写在 配置文件里 */ // @HystrixCommand 开启线程隔离 和 降级处理 @HystrixCommand( commandProperties = { // 设置断路器请求量预值, 每10次统计一次 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 休眠时间窗 10秒 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 错误百分比 60% @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), } ) public String queryById(@PathVariable("id") Long id){ // 负载均衡算法: 随机, 轮询. hash // 1. 在注册restTemplate上加注解@LoadBalanced // 2. 直接写路径 if (id % 2 == 0) { throw new RuntimeException(""); } String url = "http://user-service/user/" + id; String user = restTemplate.getForObject(url, String.class); return user; } /** * 调用失败时, 启动的方法 (这个方法必须跟成功的方法的 返回值 参数列表 必须完全一样 因为是一对一的) * @param id * @return */ /*public String queryByIdFallback(@PathVariable("id") Long id){ return "不好意思, 服务器太拥挤了!"; }*/ /** * 因为类上面写的是通用的错误方法, 所以这里不能写参数, 返回值写String就行了. * @return */ public String defaultFallback(){ return "不好意思, 服务器太拥挤了!"; } }
-
eureka-server服务
-
配置文件
-
pom.xml
<?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>hystrix-demo</artifactId> <groupId>com.xiaoge.demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>eureka-server</artifactId> <dependencies> <!-- springcloud 注册中心 eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> </project>
-
application.yml
# 这是eureka的默认端口号 server: port: 10086 # 配置eureka服务名称 spring: application: name: eureka-server # 注册方 # 告诉eureka要注册的地址在哪里 (这样eureka就不会报一个com.sun.jersey.api.client.ClientHandlerException异常) eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka # 配置所有的eureka地址, 防止其中一个eureka挂掉 register-with-eureka: false # 默认为true 注册自己, 改为false 不 注册自己 instance: prefer-ip-address: true # 我希望使用ip地址 ip-address: 127.0.0.1 # 设置ip地址 server: eviction-interval-timer-in-ms: 60000 # 设置eureka失效剔除时长, 每隔60秒失效剔除一次, 失效剔除挂掉的eureka
-
-
启动类
-
EurekaServer
package com.xiaoge; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * @program: cloud-demo * @description: EurekaServer端 * @author: Mr.Xiao * @create: 2020-05-04 16:34 **/ @EnableEurekaServer // 启动Eureka服务 @SpringBootApplication public class EurekaServer { public static void main(String[] args) { SpringApplication.run(EurekaServer.class); } }
-
user-service服务
-
配置文件
-
pom.xml
<?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>hystrix-demo</artifactId> <groupId>com.xiaoge.demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>user-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> </dependency> <!-- 引入eureka(注册中心)-客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> </project>
-
application.yml
server: port: 9090 spring: # 在eureka中注册的服务名称 application: name: user-service # 数据库连接信息配置 datasource: url: jdbc:mysql://localhost:3306/yun6 username: root password: root hikari: maximum-pool-size: 20 minimum-idle: 10 # 别名包 mybatis: type-aliases-package: com.xiaoge.user.pojo # 注册方 # eureka配置 因为它要去注册中心注册, 所以要配置 eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka, http://127.0.0.1:10087/eureka # 配置所有的eureka地址, 防止其中一个eureka挂掉 instance: prefer-ip-address: true # 我希望使用ip地址 ip-address: 127.0.0.1 # 设置ip地址 lease-renewal-interval-in-seconds: 30 # 每隔30秒发一次心跳 lease-expiration-duration-in-seconds: 90 # 每隔30秒发一次心跳, 如果隔了90秒都没发, 那就证明挂了
-
-
启动类
-
UserApplication
package com.xiaoge; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import tk.mybatis.spring.annotation.MapperScan; /** * @program: cloud-demo * @description: 服务的提供方 * @author: Mr.Xiao * @create: 2020-05-04 15:43 **/ @EnableDiscoveryClient // 它也是客户端, 它捷能兼容eureka 又能consul、zookeeper等等, 更通用, 更广泛 @SpringBootApplication @MapperScan("com.xiaoge.user.mapper") public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class); } }
-
-
实体类
-
User
package com.xiaoge.user.pojo; import lombok.Data; import tk.mybatis.mapper.annotation.KeySql; import javax.persistence.Id; import javax.persistence.Table; import java.io.Serializable; import java.util.Date; /** * @program: cloud-demo * @description: * @author: Mr.Xiao * @create: 2020-05-04 15:46 **/ @Table(name = "tb_user") @Data public class User implements Serializable { @Id @KeySql(useGeneratedKeys = true) // id自动增长 private Long id; // 用户名 private String username; // 密码 private String password; // 姓名 private String name; // 年龄 private Integer age; // 性别,1男性,2女性 private Integer sex; // 出生日期 private Date birthday; // 创建时间 private Date created; // 更新时间 private Date updated; // 备注 private String note; }
-
-
表现层
-
UserController
package com.xiaoge.user.controller; import com.xiaoge.user.pojo.User; import com.xiaoge.user.service.UserService; import org.apache.tomcat.jni.Time; import org.springframework.beans.factory.annotation.Autowired; 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; /** * @program: cloud-demo * @description: * @author: Mr.Xiao * @create: 2020-05-04 15:51 **/ @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/{id}") public User queryById(@PathVariable("id") Long id) { User user = userService.queryById(id); return user; } }
-
-
业务层
-
UserService接口
package com.xiaoge.user.service; import com.xiaoge.user.pojo.User; /** * @program: cloud-demo * @description: * @author: Mr.Xiao * @create: 2020-05-04 15:50 **/ public interface UserService { public User queryById(Long id); }
-
UserServiceImpl实体类
package com.xiaoge.user.service.impl; import com.xiaoge.user.mapper.UserMapper; import com.xiaoge.user.pojo.User; import com.xiaoge.user.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @program: cloud-demo * @description: * @author: Mr.Xiao * @create: 2020-05-04 15:51 **/ @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User queryById(Long id) { return userMapper.selectByPrimaryKey(id); } }
-
-
Mapper
-
UserMapper
package com.xiaoge.user.mapper; import com.xiaoge.user.pojo.User; import tk.mybatis.mapper.common.Mapper; /** * @program: cloud-demo * @description: * @author: Mr.Xiao * @create: 2020-05-04 15:49 **/ public interface UserMapper extends Mapper<User> { }
-