目录
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的字节码
string url = "http: //userservice/user/" + order.getUserId();
User user = restTemplate.getFor0bject(url,User.class);
存在下面的问题:
代码可读性差,编程体验不统一
参数复杂URL难以维护
1.引入依赖:
在orderservice的pom文件引入依赖
org.springframework.cloud spring-cloud-starter-openfeign
cloud-demo
cn.itcast.demo
1.0
4.0.0
order-service
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
org.mybatis.spring.boot
mybatis-spring-boot-starter
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.boot
spring-boot-maven-plugin
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
@LoadBalanced
public 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 {
@Autowired
private OrderMapper orderMapper;
@Autowired
private 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到order
order.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都能访问,并且是负载均衡的
方式一:配置文件方式,在orderservice的application.yml文件添加
1、全局生效:
feign: client: config: default: #这里填default是全局生效,填服务名就是局部生效 loggerLevel: FULL #显示完整信息
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
username: root
password: 1234
driver-class-name: com.mysql.jdbc.Driver
application:
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.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
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=false
username: root
password: 1234
driver-class-name: com.mysql.jdbc.Driver
application:
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.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
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 {
@Bean
public 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
@LoadBalanced
public 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的支持:
引入依赖
io.github.openfeign feign-httpclient
配置连接池
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=false
username: root
password: 1234
driver-class-name: com.mysql.jdbc.Driver
application:
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.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
cn.itcast: debug
pattern:
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 #单个请求路径的最大连接数
方式一(继承)︰给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。
方式二(抽取)︰将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用
这里我只实现方式二
1.首先创建一个module,命名为feign-api,然后引入feign的starter依赖
org.springframework.cloud spring-cloud-starter-openfeign
cloud-demo
cn.itcast.demo
1.0
4.0.0
feign-api
8
8
org.springframework.cloud
spring-cloud-starter-openfeign
2.将order-service中编写的UserClient、User、DefaultFeignConfiguration都剪切到feign-api项目中
因为这些代码移到其他模块了,所以会报错
①UserClient的User报错,重新导包,用feign包内的User
②Orderservice的Order依赖User报错,在pom文件引入依赖,并重新导包,用feign模块的包
cn.itcast.demo feign-api 1.0
cloud-demo
cn.itcast.demo
1.0
4.0.0
order-service
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
org.mybatis.spring.boot
mybatis-spring-boot-starter
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-openfeign
io.github.openfeign
feign-httpclient
cn.itcast.demo
feign-api
1.0
org.springframework.boot
spring-boot-maven-plugin
③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
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
// @Bean
// public IRule randomRule(){
// return new RandomRule();//将负载均衡设置为随机,范围为整个order
// }
}
访问数据,请求成功
代码文件点击下载https://pan.baidu.com/s/1GooYipFzcnCyubANjf5S6Q?pwd=vpea上一篇:Nacos配置管理
下一篇:Gateway