目录
RestTemplate方式调用存在的问题:
定义和使用Feign客户端
自定义Feign的配置
性能优化
Feign的最佳实践
Feign的使用步骤:
1、引入依赖
2、添加@EnableFeignClients注解3、编写FeignClient接口
4、使用FeignClient中定义的方法代替RestTemplate
Feign的日志配置:
1、方式一是配置文件,feign.client.config.xxx.loggerLevel
①如果xxx是default则代表全局
②如果xxx是服务名称,例如userservice则代表某服务2、方式二是java代码配置Logger.Level这个Bean
①如果在@EnableFeignClients注解声明则代表全局②如果在@FeignClient注解中声明则代表某服务
Feign的优化:命
1、日志级别尽量用basic
2、使用Httpclient或OKHttp代替URLConnection
引入feign-httpClient依赖
配置文件开启httpClient功能,设置连接池参数Feign的最佳实践:
1、让controller和FeignClient继承同一接口
2、将FeignClient、POJO、Feign的默认配置都定义到一个项目中,供所有消费者使用不同包的FeignClient的导入有两种方式:
1、在@EnableFeignClients注解中添加basePackages,指定FeignClient所在的包
2、在@EnableFeignClients注解中添加clients,指定具体Feignclient的字节码
RestTemplate方式调用存在的问题:
string url = "http: //userservice/user/" + order.getUserId();
User user = restTemplate.getFor0bject(url,User.class);
存在下面的问题:
代码可读性差,编程体验不统一
参数复杂URL难以维护
定义和使用Feign客户端
1.引入依赖:
在orderservice的pom文件引入依赖
<!--feign客户端依赖--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
<?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>cloud-demo</artifactId><groupId>cn.itcast.demo</groupId><version>1.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>order-service</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!--eureka客户依赖-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>--><!-- nacos客户端依赖包 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--feign客户端依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
2.在order-service的启动类添加注解开启Feign的功能:
在orderservice的启动类中添加注解
@EnableFeignClients
package cn.itcast.order;import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}//创建RestTemplate并注入Spring容器@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}// @Bean
// public IRule randomRule(){
// return new RandomRule();//将负载均衡设置为随机,范围为整个order
// }
}
3.编写Feign客户端:
添加一个包,并写一个接口,再引入客户端注解FeignClient
package cn.itcast.order.clients;import cn.itcast.order.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient("userservice")
public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);
}
4、改造orderservice的service.java文件,把以前写的RestTemplate方式换成Feign方式
package cn.itcast.order.service;import cn.itcast.order.clients.UserClient;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import cn.itcast.order.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate UserClient userClient;public Order queryOrderById(Long orderId) {// 1.查询订单Order order = orderMapper.findById(orderId);// 2.用Feign远程调用// 2.1.url路径User user = userClient.findById(order.getUserId());// 3.封装user到orderorder.setUser(user);// 4.返回return order;}// @Autowired
// private RestTemplate restTemplate;
//
// public Order queryOrderById(Long orderId) {
// // 1.查询订单
// Order order = orderMapper.findById(orderId);
// // 2.利用RestTemplate发送http请求,查询用户
// // 2.1.url路径
// String url = "http://userservice/user/" + order.getUserId();
// // 2.2.发送http请求,实现远程调用
// User user = restTemplate.getForObject(url, User.class);//第一个参数是路径,第二个参数是返回的类=类型
// // 3.封装user到order
// order.setUser(user);
// // 4.返回
// return order;
// }
}
访问数据,可以发现:两个userservice都能访问,并且是负载均衡的
自定义Feign的配置
方式一:配置文件方式,在orderservice的application.yml文件添加
1、全局生效:
feign:client:config:default: #这里填default是全局生效,填服务名就是局部生效loggerLevel: FULL #显示完整信息
server:port: 8080
spring:datasource:url: jdbc:mysql://localhost:3306/cloud_order?useSSL=falseusername: rootpassword: 1234driver-class-name: com.mysql.jdbc.Driverapplication:name: orderservice #order的微服务名称cloud:nacos:server-addr: localhost:8848
# discovery:
# cluster-name: HZ #集群名称
# namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
# ephemeral: false #是否为临时实例
mybatis:type-aliases-package: cn.itcast.user.pojoconfiguration:map-underscore-to-camel-case: true
logging:level:cn.itcast: debugpattern:dateformat: MM-dd HH:mm:ss:SSS
#eureka:
# client:
# service-url: #eureka地址信息1
# defaultZone: http://127.0.0.1:10086/eureka
userservice:ribbon:NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:eager-load:enabled: true #开启饥饿加载clients: #指定饥饿加载的服务- userservice
feign:client:config:default: #这里填default是全局生效,填服务名就是局部生效loggerLevel: FULL #显示完整信息
可以看到只是访问一次数据,就有很多信息
2、局部生效:
feign:client:config:userservice: #这里填default是全局生效,填服务名就是局部生效loggerLevel: FULL #显示完整信息
方式二: java代码方式,需要先声明一个Bean:
先把方式一的代码注释掉
#feign: # client: # config: # default: #这里填default是全局生效,填服务名就是局部生效 # loggerLevel: FULL #显示完整信息
server:port: 8080
spring:datasource:url: jdbc:mysql://localhost:3306/cloud_order?useSSL=falseusername: rootpassword: 1234driver-class-name: com.mysql.jdbc.Driverapplication:name: orderservice #order的微服务名称cloud:nacos:server-addr: localhost:8848
# discovery:
# cluster-name: HZ #集群名称
# namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
# ephemeral: false #是否为临时实例
mybatis:type-aliases-package: cn.itcast.user.pojoconfiguration:map-underscore-to-camel-case: true
logging:level:cn.itcast: debugpattern:dateformat: MM-dd HH:mm:ss:SSS
#eureka:
# client:
# service-url: #eureka地址信息1
# defaultZone: http://127.0.0.1:10086/eureka
userservice:ribbon:NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:eager-load:enabled: true #开启饥饿加载clients: #指定饥饿加载的服务- userservice
#feign:
# client:
# config:
# default: #这里填default是全局生效,填服务名就是局部生效
# loggerLevel: FULL #显示完整信息
先添加一个包config,再添加一个DefaultFeignConfiguration.java
package cn.itcast.order.config;import feign.Logger;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfiguration {@Beanpublic Logger.Level logLevel(){return Logger.Level.BASIC;}
}
1、如果是全局配置,则把它放到@EnableFeignClients这个注解中:
@EnableFeignClients(defaultConfiguration = FeignclientConfiguration.class)
添加在启动类上:
package cn.itcast.order;import cn.itcast.order.config.DefaultFeignConfiguration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}//创建RestTemplate并注入Spring容器@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}// @Bean
// public IRule randomRule(){
// return new RandomRule();//将负载均衡设置为随机,范围为整个order
// }
}
请求数据,可以看到比起方式一,这种方式的信息简洁许多。因为第一种方式用的FULL,而第二种方式是BASIC
2、如果是局部配置,则把它放到@FeignClient这个注解中:
@FeignClient(value = "userservice", configuration = FeignClientConfiguration.class)
添加在UserClient.interface上,这里就不再做演示了。
性能优化
Feign添加HttpClient的支持:
引入依赖
<!--引入httpClient依赖--> <dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId> </dependency>
配置连接池
feign:httpclient:enabled: true #支持httpclient的开关max-connections: 200 #最大连接数max-connections-per-route: 50 #单个请求路径的最大连接数
server:port: 8080
spring:datasource:url: jdbc:mysql://localhost:3306/cloud_order?useSSL=falseusername: rootpassword: 1234driver-class-name: com.mysql.jdbc.Driverapplication:name: orderservice #order的微服务名称cloud:nacos:server-addr: localhost:8848
# discovery:
# cluster-name: HZ #集群名称
# namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
# ephemeral: false #是否为临时实例
mybatis:type-aliases-package: cn.itcast.user.pojoconfiguration:map-underscore-to-camel-case: true
logging:level:cn.itcast: debugpattern:dateformat: MM-dd HH:mm:ss:SSS
#eureka:
# client:
# service-url: #eureka地址信息1
# defaultZone: http://127.0.0.1:10086/eureka
userservice:ribbon:NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:eager-load:enabled: true #开启饥饿加载clients: #指定饥饿加载的服务- userservice
feign:httpclient:enabled: true #支持httpclient的开关max-connections: 200 #最大连接数max-connections-per-route: 50 #单个请求路径的最大连接数
Feign的最佳实践
方式一(继承)︰给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。
方式二(抽取)︰将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用
这里我只实现方式二
1.首先创建一个module,命名为feign-api,然后引入feign的starter依赖
<!--引入feign依赖--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
<?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>cloud-demo</artifactId><groupId>cn.itcast.demo</groupId><version>1.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>feign-api</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies></project>
2.将order-service中编写的UserClient、User、DefaultFeignConfiguration都剪切到feign-api项目中
因为这些代码移到其他模块了,所以会报错
①UserClient的User报错,重新导包,用feign包内的User
②Orderservice的Order依赖User报错,在pom文件引入依赖,并重新导包,用feign模块的包
<!--引入feign的统一依赖--> <dependency><groupId>cn.itcast.demo</groupId><artifactId>feign-api</artifactId><version>1.0</version> </dependency>
<?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>cloud-demo</artifactId><groupId>cn.itcast.demo</groupId><version>1.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>order-service</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><!--eureka客户依赖-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>--><!-- nacos客户端依赖包 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--feign客户端依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--引入httpClient依赖--><dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId></dependency><!--引入feign的统一依赖--><dependency><groupId>cn.itcast.demo</groupId><artifactId>feign-api</artifactId><version>1.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
③Orderservice的Orderservice报错,重新导入feign模块下的包
④Orderservice的启动类报错,导入feign模块的包
⑤当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。
有两种方式解决:
方式一:指定FeignClient所在包
@EnableFeignclients(basePackages = "cn.itcast.feign.clients")
方式二:指定Feignclient字节码
@EnableFeignclients(clients = {Userclient.class})
在order的启动类的EnableFeignclients加一个属性
@EnableFeignClients(clients = UserClient.class, defaultConfiguration = DefaultFeignConfiguration.class)
我这里使用第一个方式
package cn.itcast.order;import cn.itcast.feign.clients.UserClient;
import cn.itcast.feign.config.DefaultFeignConfiguration;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(clients = UserClient.class, defaultConfiguration = DefaultFeignConfiguration.class)
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}//创建RestTemplate并注入Spring容器@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}// @Bean
// public IRule randomRule(){
// return new RandomRule();//将负载均衡设置为随机,范围为整个order
// }
}
访问数据,请求成功
代码文件点击下载https://pan.baidu.com/s/1GooYipFzcnCyubANjf5S6Q?pwd=vpea上一篇:Nacos配置管理