Ribbon
RestTemplate
如果RestTemplate要通过服务名称作为URI参数来调用方法,那么restTemplate必须加@LoadBalanced注解
@RestController
@Slf4j
public class OrderController {
// private static final String PAYMENT_URL = "http://localhost:8001";
private static final String PAYMENT_URL = "http://CLOUD-PROVIDER-PAYMENT";//服务提供者的spring.application.name
@Configuration
public class ApplicationContextConfig {
// @LoadBalanced //赋予restTemplate负载均衡的能力
@Bean
public RestTemplate myRestTemplate(){
return new RestTemplate();
}
}
负载规则
restTemplate默认使用轮询算法
自定义负载规则
- 仍然使用@LoadBalanced注解
可以通过实现IRule接口,来自定义规则,再通过@Bean注解放入容器即可,不做演示。
重点:自定义的rule所不要和主配置类同级,最好是高一级的包,主配置类使用@RibbonClient引入即可
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
//@RibbonClient(name = "cloud-provider-payment",configuration = MyRule.class)
public class Order80 {
public static void main(String[] args) {
SpringApplication.run(Order80.class,args);
}
}
- 不使用@LoadBanlanced注解
以下自定义了一个接口,和该接口实现类,具体含义不多赘述
接口
public interface LoadBalancer {
ServiceInstance getServer(List<ServiceInstance> servers);
}
实现类
@Component
public class MyLoadBalancer implements LoadBalancer{
private final AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public ServiceInstance getServer(List<ServiceInstance> servers) {
int index = getIndex() % servers.size();
return servers.get(index);
}
/**
* 获取下标,并自增
* @return
*/
public final int getIndex(){
int current ;
int next;
do {
current = atomicInteger.get();
next = current >= 2147483647 ? 0 : current + 1;
} while (!atomicInteger.compareAndSet(current,next));
System.out.println("*****当前是第"+next+"次访问*****");
return next;
}
}
controller
@GetMapping("consumer/payment/lb")
public String selectLoadBalancer(){
List<ServiceInstance> servers = discoveryClient.getInstances("CLOUD-PROVIDER-PAYMENT");
ServiceInstance server = loadBalancer.getServer(servers);
URI uri = server.getUri();
System.out.println(uri);
return restTemplate.getForObject(uri+"/payment/lb",String.class);
}
OpenFeign
OpenFeign就是对RestTemplate的再封装,我们只需要提供一个接口,并使用@FeignCilent指定服务提供者的名称即可
pom
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ganxie.xiaowen.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka
spring:
application:
name: cloud-order-feign
主启动类
@SpringBootApplication
@EnableFeignClients
public class Feign80 {
public static void main(String[] args) {
SpringApplication.run(Feign80.class,args);
}
}
业务
接口
@Component
@FeignClient(name = "cloud-provider-payment")
public interface PaymentService {
@GetMapping("/payment/{id}")
CommonResult<Payment> selectById(@PathVariable("id") Long id);
@GetMapping("/payment/timeout")
String feignTimeout();
}
controller
@RestController
@Slf4j
public class OrderController {
@Resource
private PaymentService paymentService;
@GetMapping("/consumer/payment/{id}")
public CommonResult<Payment> selectById(@PathVariable("id") Long id){
return paymentService.selectById(id);
}
@GetMapping("/consumer/payment/timeout")
public String feignTimeout() {
return paymentService.feignTimeout();
}
}
超时控制
openfeign默认连接时间是一秒,如果超过一秒会报错
可以通过配置文件修改默认时间
#feign超时控制
ribbon:
# 指的是建立连接后从服务器读取到可用资源所用的时间
ReadTimeout: 5000
# 建立连接所用的时间,适用于网络状况正常情况下,两端连接所用的时间
ConnecTimeout: 5000
日志增强
容器注入,一共有四个等级
/**
* Controls the level of logging.
*/
public enum Level {
/**
* No logging.
*/
NONE,
/**
* Log only the request method and URL and the response status code and execution time.
*/
BASIC,
/**
* Log the basic information along with request and response headers.
*/
HEADERS,
/**
* Log the headers, body, and metadata for both requests and responses.
*/
FULL
}
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLever(){
return Logger.Level.FULL;
}
}
配置文件指定
logging:
level:
ganxie.xiaowen.service.PaymentService: debug