目录
OpenFeign是什么
OpenFeign是SpringCloud提供的声明式HTTP客户端,能够使用SpringMVC的注解实现远程服务的调用
实现服务间调用的http客户端是RestTemplate,弊端是传参需要手动拼接参数
OpenFeign的使用方法
1) 加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2) 启动类加
@EnableFeignClients(basePackages = "com.blb.orderservice.client")
3) 编写接口
/**
* 调用商品服务的客户端
*/
@FeignClient("product-service")
public interface ProductServiceClient {
@GetMapping("/product/{id}")
ResponseEntity<Product> getProductById(@PathVariable Long id);
@GetMapping("/products-page")
ResponseEntity<Page<Product>> getProductPage(@RequestParam(required = false,defaultValue = "1")Long current,
@RequestParam(required = false,defaultValue = "5")Long size);
@PostMapping("/product")
ResponseEntity<Product> addProduct(@RequestBody Product product);
@PutMapping("/product")
ResponseEntity<Product> updateProduct(@RequestBody Product product);
@DeleteMapping("/product/{id}")
ResponseEntity<Long> deleteProduct(@PathVariable Long id);
}
4) 使用接口
在测试类中调用
@SpringBootTest
class OrderServiceApplicationTests {
@Autowired
private ProductServiceClient productServiceClient;
@Test
void contextLoads() {
Product product = new Product();
product.setId(4l);
product.setName("1");
product.setPrice(123l);
product.setType("人");
productServiceClient.update(product);
}
}
OpenFeign的优化方式
1) http客户端优化
OpenFeign默认使用JDK自带HttpConnection实现http调用,不带连接池,资源利用率低
可以选用OkHttpClient、ApacheHttpClient 或ApacheHC5 带连接池,效率更高
选用下面配置之一
feign.okhttp.enabled=true
feign.httpclient.enabled=true
feign.httpclient.hc5.enabled=true
2) 请求响应压缩
将请求和响应数据进行压缩,占用带宽小,速度更快
feign.compression.request.enabled=true
feign.compression.response.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048
3) 日志跟踪
写一个配置类
NONE 没有,默认
BASIC 基本的方法名、URL、响应码
HEADER 请求和响应头
FULL 完整,包含完整的请求响应报文
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
在application.properties中加
logging.level.com.blb.orderservice.client.ProductServiceClient: debug
重新测试时,会有日志记录
4) 启动熔断器
在application.properties中加
feign.hystrix.enabled=true
编写熔断降级类
@Component
public class ProductServiceClientFackback implements ProductServiceClient{
@Override
public ResponseEntity<Product> getProductById(Long id) {
Product product = new Product();
product.setName("降级数据");
return ResponseEntity.ok(product);
}
}
设置降级类
@FeignClient(value = "product-service",fallback = ProductServiceClientFackback.class)
OpenFeign的实现原理
为什么只用写个接口就能实现远程服务的调用??
需要使用技术:
1) 接口的扫描(IOC 扫描包 + 反射读取接口信息)
2) 接口的实现(JDK的动态代理,创建接口的实现类返回对象)
3) 调用的过程
读取FeignClient中的服务名,到注册中心查询服务的IP和端口
请求编码:将IP和端口以及接口定义URL和参数拼接起来
使用配置的HTTP客户端发送请求,获得响应结果
响应解码:对响应结果进行解码,返回数据
Gateway是什么
SpringCloud提供的API网关组件,主要的作用是:统一的路由和鉴权,能够提高微服务系统的安全性
我们可以将微服务的IP和端口隐藏起来,唯一暴露出来的就是网关的端口,前端的请求都通过网关路由到每个微服务
Gateway的入门
1) 新建微服务项目
2) 注册到nacos上
3) 配置路由规则
Gateway的路由规则
按路径转发某个服务
server:
port: 9000
spring:
application:
name: gateway-service
cloud:
nacos:
config: #配置中心的配置
server-addr: 127.0.0.1:8848
gateway:
routes: # 路由规则
- id: product-service-route # 路由名称
uri: lb://product-service # 路由的服务
predicates: # 包含路径
- Path=/product/**,/product-add,/product-update
Gateway的过滤器
Gateway网关可以通过过滤器对请求进行权限验证
Gateway运行的过程:
1) 客户端发送请求给Gateway
2) Gateway将请求交给处理器映射
3) 处理器映射通过路由规则找到处理器
4) 处理器将请求发送给被代理的服务,请求会经过一个过滤器链
5) 过滤器有前置后置两种,前置过滤器可以执行逻辑判断,对请求进行拦截
6) 后置过滤器可以在响应数据上添加内容或进行日志收集等
过滤器按影响范围分为:
1) 局部过滤器(影响部分路由)
2) 全局过滤器(影响所有路由)
案例: 全局过滤器验证Token,验证失败不允许访问服务
/**
* 全局Token验证的过滤器
*/
@Component
public class TokenFilter implements GlobalFilter, Ordered {
/**
* 过滤
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获得请求和响应
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//获得token参数
String token = request.getQueryParams().getFirst("token");
//验证token,成功就放行
if("123456".equals(token)){
return chain.filter(exchange);
}
//设置401响应码
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//保证响应信息
DataBuffer wrap = response.bufferFactory().wrap("Login Failed".getBytes());
//返回数据给客户端
return response.writeWith(Mono.just(wrap));
}
@Override
public int getOrder() {
// 值越大,过滤器执行越靠后
return 0;
}
}