package com.springcloud.lesson8.web.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Random;
import java.util.concurrent.TimeoutException;
@RestController
public class DemoRestController {
private final static Random random = new Random();
/**
* 当方法执行时间超过100ms时,触发异常
* @return
*/
@GetMapping("")
public String index() throws Exception {
long executeTIme = random.nextInt(200);
if (executeTIme > 100) { // 执行超过100ms
throw new TimeoutException("Execution is timeout");
}
return "Hello World";
}
}
package com.springcloud.lesson8.web.controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.concurrent.TimeoutException;
/**
* @author <a href="mailto:[email protected]">Finen</a>
* @description {@link DemoRestController} 类似于aop拦截
* @see {@link DemoRestController} {@link DemoRestControllerAdvice}
* @since 0.0.1
*/
@RestControllerAdvice(assignableTypes = DemoRestController.class)
public class DemoRestControllerAdvice {
@ExceptionHandler(TimeoutException.class)
public Object faultToleranceTimeout(Throwable throwable) {
return throwable.getMessage();
}
}
<dependencyManagement>
<dependencies>
<!-- Spring Boot 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>version>2.3.9.RELEASE</version>
</dependency>
<!-- Spring Cloud 依赖 -->
<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>
修改应用 user-service-provider
的引导类:
package com.springclouid.lesson8;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
@SpringBootApplication
@EnableHystrix
public class UserServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceProviderApplication.class, args);
}
}
增加 getUsers()
方法到 UserServiceProviderController
:
@RestController
public class UserServiceProviderController {
@Autowired
private UserService userService;
private final static Random random = new Random();
@PostMapping("/user/save")
public boolean saveUser(@RequestBody User user) {
return userService.saveUser(user);
}
/**
* 增加超时处理
* @return
*/
@HystrixCommand(
commandProperties = {
// 设置超时时间返回100ms
@HystrixProperty(name = "execution.isolation.thread.timeoutInMillisecond", value = "100")
},
fallbackMethod = "fallbackForGetUsers" // 设置fallback方法
)
@GetMapping("/user/list")
public Collection<User> getUsers() throws InterruptedException {
long executeTime = random.nextInt(200);
// 休眠时间
System.out.println("execute time" + executeTime);
Thread.sleep(executeTime);
return userService.findAll();
}
/**
* {@link #getUsers()} 的fallback方法
* @return
*/
public Collection<User> fallbackForGetUsers() {
return Collections.emptyList();
}
}
为 getUsers()
添加 fallback 方法:
/**
* {@link #getUsers()} 的 fallback 方法
*
* @return 空集合
*/
public Collection<User> fallbackForGetUsers() {
return Collections.emptyList();
}
调整 user-ribbon-client
,为UserRibbonController
增加获取用户列表,实际调用user-service-provider
"/user/list" REST 接口
在UserRibbonClientApplication
增加 RestTemplate
申明
/**
* 申明 具有负载均衡能力 {@link RestTemplate}
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
/**
* 调用 user-service-provider "/user/list" REST 接口,并且直接返回内容
* 增加 短路功能
*/
@GetMapping("/user-service-provider/user/list")
public Collection<User> getUsersList() {
return restTemplate.getForObject("http://" + providerServiceName + "/user/list", Collection.class);
}
package com.springclouid.lesson8;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.springclouid.lesson8.user.ribbon.client.ping.MyPing;
import com.springclouid.lesson8.user.ribbon.client.rule.MyRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@RibbonClient("user-service-provider") // 指定目标应用名称
@EnableCircuitBreaker
public class UserRibbonClientApplication {
public static void main(String[] args) {
SpringApplication.run(UserRibbonClientApplication.class, args);
}
/**
* 将 {@link MyRule} 暴露成 {@link Bean}
* @return {@link MyRule}
*/
@Bean
public IRule myRule() {
return new MyRule();
}
/**
* 将 {@link MyPing} 暴露成 {@link Bean}
* @return {@link MyPing}
*/
@Bean
public IPing myPing() {
return new MyPing();
}
/**
* 申明具有负载均衡能力的{@link RestTemplate}
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
package com.springclouid.lesson8.user.ribbon.client.hystrix;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
import java.util.Collections;
/**
* @author <a href="mailto:[email protected]">Finen</a>
* @description
* @see
* @since
*/
public class UserRibbonClientHystrixCommand extends HystrixCommand<Object> {
private final RestTemplate restTemplate;
private final String providerServiceName;
public UserRibbonClientHystrixCommand(RestTemplate restTemplate, String providerServiceName) {
super(HystrixCommandGroupKey.Factory.asKey(
"User-Ribbon-Client"),
100);
this.restTemplate = restTemplate;
this.providerServiceName = providerServiceName;
}
@Override
protected Object run() throws Exception {
return restTemplate.getForObject("http://" + providerServiceName + "/user/list", Collection.class);
}
/**
* Fallback 实现
* @return
*/
protected Object getFallback() {
return Collections.emptyList();
}
}
package com.springclouid.lesson8.user.ribbon.client.web.controller;
import com.springclouid.lesson8.domain.User;
import com.springclouid.lesson8.user.ribbon.client.hystrix.UserRibbonClientHystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.Collection;
@RestController
public class UserRibbonController {
@Autowired
private RestTemplate restTemplate;
/**
* 负载均衡器客户端
*/
@Autowired
private LoadBalancerClient loadBalancerClient;
@Value("${provider.service.name}")
private String providerServiceName;
private UserRibbonClientHystrixCommand hystrixCommand;
@GetMapping("")
public String index() throws IOException {
User user = new User();
user.setId(1L);
user.setName("xiaoming");
//选择服务
ServiceInstance serviceInstance = loadBalancerClient.choose(providerServiceName);
return loadBalancerClient.execute(providerServiceName, serviceInstance, instance -> {
// 服务器实例
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/user/save";
RestTemplate restTemplate = new RestTemplate();
return restTemplate.postForObject(url, user, String.class);
});
}
/**
* 调用 user-service-provider "/user/list",并直接返回内容
* 增加 短路功能
*/
@GetMapping("/user-service-provider/user/list")
public Collection<User> getUserList() {
return new UserRibbonClientHystrixCommand(restTemplate, providerServiceName).execute();
}
}
<dependencies>
<!-- 依赖 Hystrix Dashboard -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
package com.spring.cloud.hystrix.dashboard;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author <a href="mailto:[email protected]">Finen</a>
* @description
* @see
* @since
*/
@SpringBootApplication
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}
}
## Hystrix Dashboard 应用
spring.application.name = hystrix-dashboard
## 服务端口
server.port = 10000