Hystrix熔断器整合 - 搭建项目

实战前需了解:https://blog.csdn.net/wanzijy/article/details/125041622
Hystrix熔断器整合 - 搭建项目:https://blog.csdn.net/wanzijy/article/details/125496651
Hystrix熔断器整合 - 请求缓存:https://blog.csdn.net/wanzijy/article/details/125512072
Hystrix熔断器整合 - 请求合并:https://blog.csdn.net/wanzijy/article/details/125579664
Hystrix熔断器整合 - 服务隔离之线程池隔离:https://blog.csdn.net/wanzijy/article/details/125630353
Hystrix熔断器整合 - 服务隔离之信号量隔离:https://blog.csdn.net/wanzijy/article/details/125826690
Hystrix熔断器整合 - 服务熔断和服务降级:https://blog.csdn.net/wanzijy/article/details/125826853
Hystrix熔断器整合 - Feign实现服务容错:https://blog.csdn.net/wanzijy/article/details/125985304
Hystrix熔断器整合 - 可视化界面三部曲:https://blog.csdn.net/wanzijy/article/details/126005452

1. 项目结构

项目结构
项目介绍:

  • eureka-server 注册中心1
  • eureka-server02 注册中心2
  • product-service 商品服务
  • order-service-rest 订单服务,用于远程调用商品服务

2. 父项目的pom.xml

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<maven.compiler.source>8</maven.compiler.source>
	<maven.compiler.target>8</maven.compiler.target>
	<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
</properties>

<packaging>pom</packaging>

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.2.4.RELEASE</version>
	<relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>${spring-cloud.version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

3. eureka-server 模块

3.1 pom.xml

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
		<exclusions>
			<exclusion>
				<groupId>org.junit.vintage</groupId>
				<artifactId>junit-vintage-engine</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
</dependencies>

3.2 application.yml

spring:
  application:
    name: eureka-server

server:
  port: 8761

eureka:
  instance:
    hostname: eureka01  #  主机名,不配置的时候将根据操作系统的主机名来获取
    prefer-ip-address: false  #  是否使用 ip 地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port}  #  ip:port
  client:
    register-with-eureka: true
    fetch-registry: true
    #  设置服务注册中心地址,指向另一个注册中心
    service-url:  #  对外暴露的注册地址
      defaultZone: http://eureka02:8762/eureka/

3.3 启动类

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

}

4. eureka-server02 模块

4.1 pom.xml

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
		<exclusions>
			<exclusion>
				<groupId>org.junit.vintage</groupId>
				<artifactId>junit-vintage-engine</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
</dependencies>

4.2 application.yml

spring:
  application:
    name: eureka-server

server:
  port: 8762

eureka:
  instance:
    hostname: eureka02  #  主机名,不配置的时候将根据操作系统的主机名来获取
    prefer-ip-address: false  #  是否使用 ip 地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port}  #  ip:port
  client:
    register-with-eureka: true
    fetch-registry: true
    #  设置服务注册中心地址,指向另一个注册中心
    service-url:  #  对外暴露的注册地址
      defaultZone: http://eureka01:8761/eureka/

4.3 启动类

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication02 {

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

}

搭建完后同时启动上述两个项目,在刚开始启动时可能会在控制台报错。因为虽然说是同时启动上述两个项目,但是这次搭建的是双注册中心,Eureka01在启动时去向Eureka02注册,但是Eureka02可能还没启动成功,所以一开始会报错,反过来Eureka02向Eureka01注册时也是一样,稍微等待一会即可

Eureka01
Eureka01

Eureka02
Eureka02
如果上述双注册中心搭建不成功,看我的另一篇文章,检查里面要注意的地方:

https://blog.csdn.net/wanzijy/article/details/125101677

5. product-service 模块

5.1 pom.xml

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<scope>provided</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
		<exclusions>
			<exclusion>
				<groupId>org.junit.vintage</groupId>
				<artifactId>junit-vintage-engine</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
</dependencies>

5.2 application.yml

spring:
  application:
    name: product-service

server:
  port: 7070

eureka:
  instance:
    prefer-ip-address: true  #  是否使用 ip 地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port}  #  ip:port
  client:
    service-url:  #  设置服务注册中心地址
      defaultZone: http://eureka01:8761/eureka/,http://eureka02:8762/eureka/
    register-with-eureka: true
    fetch-registry: true

5.3 启动类

@SpringBootApplication
@EnableEurekaClient
public class ProductServiceApplication {

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

}

5.4 pojo

@Data
public class Product {

    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;

    public Product(Integer id, String productName, Integer productNum, Double productPrice) {
        this.id = id;
        this.productName = productName;
        this.productNum = productNum;
        this.productPrice = productPrice;
    }

    public Product() {
    }
}

5.5 service

5.5.1 接口

public interface ProductService {

    List<Product> selectProductList();

    List<Product> selectProductListByIds(List<Integer> ids);

    Product selectProductListById(Integer id);

}

5.5.2 接口实现类

@Service
public class ProductServiceImpl implements ProductService{

    @Override
    public List<Product> selectProductList() {
        return Arrays.asList(
                new Product(1, "华为手机", 1, 5800D),
                new Product(2, "联想笔记本", 1, 6888D),
                new Product(3, "小米平板", 5, 2020D)
        );
    }

    @Override
    public List<Product> selectProductListByIds(List<Integer> ids) {
        List<Product> products = new ArrayList<>();
        ids.forEach(id -> products.add(new Product(id, "电视机" + id, 1, 8650D)));
        return products;
    }

    @Override
    public Product selectProductListById(Integer id) {
        return new Product(id, "冰箱", 1, 2666D);
    }

}

5.6 controller

@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("list")
    public List<Product> selectProductList() {
        return productService.selectProductList();
    }

    @GetMapping("listByIds")
    public List<Product> selectProductListByIds(@RequestParam("id") List<Integer> ids) {
        return productService.selectProductListByIds(ids);
    }

    @GetMapping("/{id}")
    public Product selectProductById(@PathVariable("id") Integer id) {
        return productService.selectProductListById(id);
    }

}

搭建完后开启项目,分别访问以下链接,看项目是否搭建成功:

  • http://localhost:7070/product/list
  • http://localhost:7070/product/listByIds?id=1&id=2
  • http://localhost:7070/product/1

比如:http://localhost:7070/product/list
在这里插入图片描述

6. order-service-rest 模块

使用 RestTemplate 远程调用 product-service

6.1 pom.xml

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<scope>provided</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
		<exclusions>
			<exclusion>
				<groupId>org.junit.vintage</groupId>
				<artifactId>junit-vintage-engine</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-commons</artifactId>
		<version>2.2.1.RELEASE</version>
		<scope>compile</scope>
	</dependency>
</dependencies>

6.2 application.yml

spring:
  application:
    name: order-service-rest

server:
  port: 9090

eureka:
  instance:
    prefer-ip-address: true  #  是否使用 ip 地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port}  #  ip:port
  client:
    service-url:  #  设置服务注册中心地址
      defaultZone: http://eureka01:8761/eureka/,http://eureka02:8762/eureka/
    register-with-eureka: true
    fetch-registry: true

6.3 启动类

@SpringBootApplication
@EnableEurekaClient
public class OrderServiceApplication {

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

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

6.4 pojo

@Data
public class Product {

    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;

    public Product(Integer id, String productName, Integer productNum, Double productPrice) {
        this.id = id;
        this.productName = productName;
        this.productNum = productNum;
        this.productPrice = productPrice;
    }

    public Product() {
    }
}
@Data
public class Order {

    private Integer id;
    private String orderNo;
    private String orderAddress;
    private Double totalPrice;
    private List<Product> productList;

    public Order(Integer id, String orderNo, String orderAddress, Double totalPrice, List<Product> productList) {
        this.id = id;
        this.orderNo = orderNo;
        this.orderAddress = orderAddress;
        this.totalPrice = totalPrice;
        this.productList = productList;
    }

    public Order() {
    }
}

6.5 service

6.5.1 接口

public interface ProductService {

    List<Product> selectProductList();

    List<Product> selectProductListByIds(List<Integer> ids);

    Product selectProductListById(Integer id);

}
public interface OrderService {

    Order selectOrderById(Integer id);

    Order queryOrderById(Integer id);

    Order searchOrderById(Integer id);
}

6.5.2 接口实现类

@Service
public class ProductServiceImpl implements ProductService{

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public List<Product> selectProductList() {
        return restTemplate.exchange(
                "http://product-service/product/list",
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Product>>() {
                }).getBody();
    }

    @Override
    public List<Product> selectProductListByIds(List<Integer> ids) {
        StringBuffer sb = new StringBuffer();
        ids.forEach(id -> sb.append("id=" + id + "&"));
        return restTemplate.getForObject("http://product-service/product/listByIds?" + sb.toString(), List.class);
    }

    @Override
    public Product selectProductListById(Integer id) {
        return restTemplate.getForObject("http://product-service/product/" + id, Product.class);
    }

}
@Service
public class OrderServiceImpl implements OrderService{

    @Autowired
    private ProductService productService;

    @Override
    public Order selectOrderById(Integer id) {
        return new Order(id, "order-001", "中国", 22788D,
                productService.selectProductList());
    }

    @Override
    public Order queryOrderById(Integer id) {
        return new Order(id, "order-002", "中国", 11600D,
                productService.selectProductListByIds(Arrays.asList(1, 2)));
    }

    @Override
    public Order searchOrderById(Integer id) {
        return new Order(id, "order-003", "中国", 2666D,
                Arrays.asList(productService.selectProductListById(5)));
    }

}

6.6 controller

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @GetMapping("/{id}/product/list")
    public Order selectOrderById(@PathVariable("id") Integer id) {
        return orderService.selectOrderById(id);
    }

    @GetMapping("/{id}/product/listByIds")
    public Order queryOrderById(@PathVariable("id") Integer id) {
        return orderService.queryOrderById(id);
    }

    @GetMapping("/{id}/product")
    public Order searchOrderById(@PathVariable("id") Integer id) {
        return orderService.searchOrderById(id);
    }

}

搭建完后开启项目,分别访问以下链接,看项目是否搭建成功:

  • http://localhost:9090/order/1/product/list
  • http://localhost:9090/order/1/product/listByIds
  • http://localhost:9090/order/1/product

比如访问:http://localhost:9090/order/1/product
在这里插入图片描述


当所有项目启动完后,Eureka的可视化界面如下:
在这里插入图片描述

7. 模拟高并发环境

7.1 修改 product-service 模块的controller

在这里插入图片描述
使其每次访问时,都先阻塞两秒

try {
	TimeUnit.SECONDS.sleep(2);  //  阻塞两秒
} catch (InterruptedException e) {
	e.printStackTrace();
}

7.2 修改 order-service-rest 模块的application

因为 Tomcat 的默认并发线程数是200,在模拟高并发是不太方便,所以将其修改得较小一点,使其比较容易模拟出高并发的环境

server:
  port: 9090
  tomcat:
    max-threads: 10  #  Tomcat 的默认并发线程数是200

因为接下来关于 Hystrix 的学习中,要使用到 Apache 的压力测试工具 JMeter ,可以去看我的另一篇关于 JMeter 的教学使用文章。学习完后,在 JMeter 中添加 http://localhost:9090/order/1/product/list 接口的压力测试

https://blog.csdn.net/wanzijy/article/details/125080317

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LF3_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值