前面已经简述了Ribbon负载均衡,从Eureka获取服务的实例在通过RestTemplate调用,并转换成需要的对象
List<Product> list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,new HttpEntity<Object>(httpHeaders), List.class).getBody();
可以发现所有的数据调用和转换都是由用户直接来完成的,我们可能不想直接访问Rest接口,如果转换回来的直接是对象而不需要直接使用RestTemplate进行转换就好了,这个时候就需要使用Feign了
复制【microcloud-consumer】 成一个新的模块【microcloud-consumer-feign】
【microcloud-consumer-feign】修改pom文件,增加对feign的支持
<?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>springcloud</artifactId>
<groupId>enjoy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-consumer-feign</artifactId>
<dependencies>
<dependency>
<groupId>enjoy</groupId>
<artifactId>microcloud-api</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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<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>
</project>
注意:这里又有版本问题,如果是Edgware或之前的版本,
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
feign的操作其实需要ribbon的支持
【microcloud-service】,新建立一个microcloud-service模块,这个模块专门定义客户端的调用接口
【microcloud-service】,修改pom文件如下
<?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>springcloud</artifactId>
<groupId>enjoy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>microcloud-service</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>enjoy</groupId>
<artifactId>microcloud-api</artifactId>
</dependency>
</dependencies>
</project>
【microcloud-service】如果要通过Feign进行远程调用,依然需要安全服务提供方的认证问题,不过在feign里面已经集成了这块功能
package cn.enjoy.feign;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignClientConfig {
@Bean
public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("admin", "enjoy");
}
}
【microcloud-service】 新建一个IProductClientService接口
package cn.enjoy.service;
import cn.enjoy.feign.FeignClientConfig;
import cn.enjoy.vo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@FeignClient(name = "MICROCLOUD-PROVIDER-PRODUCT",configuration = FeignClientConfig.class)
public interface IProductClientService {
@RequestMapping("/prodcut/get/{id}")
public Product getProduct(@PathVariable("id")long id);
@RequestMapping("/prodcut/list")
public List<Product> listProduct() ;
@RequestMapping("/prodcut/add")
public boolean addPorduct(Product product) ;
}
【microcloud-consumer-feign】 修改pom文件,引入microcloud-service 包
<dependency>
<groupId>enjoy</groupId>
<artifactId>microcloud-service</artifactId>
</dependency>
【microcloud-consumer-feign】 由于microcloud-service里面已经做了安全验证,并且后面并不直接使用RestTemplate ,删除RestConfig.java类
//package cn.enjoy.config;
//
//
//import org.springframework.cloud.client.loadbalancer.LoadBalanced;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.http.HttpHeaders;
//import org.springframework.web.client.RestTemplate;
//
//import java.nio.charset.Charset;
//import java.util.Base64;
//
//@Configuration
//public class RestConfig {
//
// @Bean
// @LoadBalanced
// public RestTemplate restTemplate() {
// return new RestTemplate();
// }
//
// @Bean
// public HttpHeaders getHeaders() { // 要进行一个Http头信息配置
// HttpHeaders headers = new HttpHeaders(); // 定义一个HTTP的头信息
// String auth = "root:enjoy"; // 认证的原始信息
// byte[] encodedAuth = Base64.getEncoder()
// .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 进行一个加密的处理
// String authHeader = "Basic " + new String(encodedAuth);
// headers.set("Authorization", authHeader);
// return headers;
// }
//
//
//}
【microcloud-consumer-feign】 修改ConsumerProductController,这个时候直接使用microcloud-service定义的服务就可以了
package cn.enjoy.controller;
import cn.enjoy.service.IProductClientService;
import cn.enjoy.vo.Product;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/consumer")
public class ConsumerProductController {
@Resource
private IProductClientService iProductClientService;
@RequestMapping("/product/get")
public Object getProduct(long id) {
return iProductClientService.getProduct(id);
}
@RequestMapping("/product/list")
public Object listProduct() {
return iProductClientService.listProduct();
}
@RequestMapping("/product/add")
public Object addPorduct(Product product) {
return iProductClientService.addPorduct(product);
}
}
可见,这个时候ConsumerProductController的代码已经简洁了不少
【microcloud-consumer-feign】修改程序主类
package cn.enjoy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients("cn.enjoy.service")
public class ConsumerFeignApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerFeignApp.class,args);
}
}
启动测试:
http://localhost/consumer/product/list
可以发现Feign在调用接口的时候自带负载均衡,这也不奇怪,因为Fegin里面内置就使用的Ribbon
可以做个测试,看下是否真的如此
【microcloud-consumer-feign】修改程序主类
package cn.enjoy;
import cn.xiangxue.config.RibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients("cn.enjoy.service")
@RibbonClient(name ="MICROCLOUD-PROVIDER-PRODUCT" ,configuration = RibbonConfig.class)
public class ConsumerFeignApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerFeignApp.class,args);
}
}
启动测试:
http://localhost/consumer/product/list
可以发现,现在的路由规则以及变成了随机访问
前面我们已经知道Feign之中最核心的作用就是将Rest服务的信息转化为接口,这其中还有其他的一些地方应该要考虑,比如:数据的压缩
Rest协议更多的传输的是文本,JSON或者XML,如果用户发送的请求很大,这个时候有必要对数据进行压缩处理,好在feign本身就提供了压缩的支持
FeignContentGzipEncodingAutoConfiguration 可以先看下这个类
虽然Feign支持压缩,但默认是不开启的
再看下FeignClientEncodingProperties,可以根据这里面的属性进行相关压缩的配置
【microcloud-consumer-feign】 修改application.yml配置文件
feign:
compression:
request:
enabled: true
mime-types: # 可以被压缩的类型
- text/xml
- application/xml
- application/json
min-request-size: 2048 # 超过2048的字节进行压缩
在构建@FeignClient注解修饰的服务客户端时,会为一个客户端都创建一个feign.Logger实例,可以利用日志来分析Feign的请求细节,不过默认 Feign的日志是不开启的。
【microcloud-consumer-feign】 修改 application.yml配置文件,增加日志信息
logging:
level:
cn.enjoy.service: DEBUG
只添加上面配置还无法实现对DEBUG日志的输出,以因为Feign客户端默认的logger.level对象定义为none级别,所以不会记录feign调用过程中的信息
【microcloud-service】修改FeignClientConfig,开启日志输出
package cn.enjoy.feign;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignClientConfig {
@Bean
public Logger.Level getFeignLoggerLevel() {
return feign.Logger.Level.FULL ;
}
@Bean
public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("admin", "enjoy");
}
}
访问:localhost/consumer/product/list
总结:Feign = RestTempate + HttpHeader + Ribbon + Eureka 综合体,使用feign大大增加了代码的灵活程度