原有问题
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private RestTemplate restTemplate;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
Order order = orderService.queryOrderById(orderId);
String url = "http://userservice/user/"+order.getUserId();
User user = restTemplate.getForObject(url,User.class);
order.setUser(user);
return order;
}
}
其中:
String url = "<http://userservice/user/"+order.getUserId()>;
User user = restTemplate.getForObject(url,User.class);
代码可读性差,编程体验不统一
参数复杂URL难以维护
Feign 概念
分布式http客户端、作用是帮助我们实现http请求的发送
原有问题改造
导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
启动类添加注解@EnableFeignClients
相关代码
现有逻辑为:
订单模块会调用用户的相关信息,对应业务为orderserivce调用userseivice方法
graph TD
orderserivce --> userseivice
而有了feign就可以把它作为一个中介
graph TD
orderserivce --> UserClient --> userseivice
被调用者相关配置 => UserService
@Slf4j
@RestController
@RequestMapping("/user")
/*@RefreshScope*/
public class UserController {
@Autowired
private UserService userService;
/**
* 路径: /user/110
*
* @param id 用户id
* @return 用户
*/
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id
,@RequestHeader(value = "Truth",required = false) String truth) {
return userService.queryById(id);
}
}
中介相关配置=>Feign
要求(Feign的)方法参数和请求方式、地址与被调用者(UserService)一致(复制粘贴的事)
import cn.itcast.feign.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);
}
其中@FeignClient("userservice")填充的值,为被调用者的application.yml中spring. application.name的值
调用者相关配置=>Order
OrderService调用feign客户端
import cn.itcast.feign.clients.UserClient;
import cn.itcast.feign.pojo.User;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class OrderService {
@Resource
private OrderMapper orderMapper;
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// feign 远程调用
User user = userClient.findById(order.getUserId());
// 封装user 和order
order.setUser(user);
// 4.返回
return order;
}
}
OrderController直接调用orderService层方法
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
Order order = orderService.queryOrderById(orderId);
return order;
}
}
调用者的启动类上添加注解
@EnableFeignClients(clients = UserClient.class, defaultConfiguration = DefaultFeignConfiguration.class)
@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);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
/*
@Bean
public IRule randomRule(){
return new RandomRule();
}*/
}
自定义配置
类似案例
可以参考这篇:juejin.cn/post/725189…
配置日志
方式一
全局生效
对于一切访问的微服务都生效
feign:
client:
config:
default:
loggerLevel: FULL
局部生效
只针对某个微服务配置
feign:
client:
config:
ueseservice:
loggerLevel: FULL
方式二
申明一个bean对象
import feign.Logger;
import org.springframework.context.annotation.Bean;
public class DefaultFeignConfiguration {
@Bean
public Logger.Level logLevel(){
return Logger.Level.BASIC;
}
}
全局配置
修改启动器注解:@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
局部生效
修改启动器注解:@EnableFeignClients(value = "userservice", defaultConfiguration = DefaultFeignConfiguration.class)
性能调优
feign客户端实现方式:
URLConnection : 默认实现,不支持连接池
Apache HttpClient : 支持连接池
OKHttp : 支持连接池
因此使用带连接池的替代默认URLConnection
连接池配置
导入依赖
<!--HttpClient 依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
配置连接池
feign:
httpclient:
enabled: true
max-connections: 200
max-connections-per-route: 50
ps : 日志级别,最好使用basic或none
实践方案
方法一
继承:给消费者的FeignClient和提供者的controller定义统一的父接口作为标准
方法二
抽取:将FeignClient抽离为独立模块,并将接口有关的POJO,默认的Feign配置都放到这个模块中,提供给所有消费者使用
新建feign-api模块,引入starter依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
复制UserClient,User,Congifuration到feign-api项目中
在调用者order-service的依赖中引入feigin-api
<!--引入feign的统一api-->
<dependency>
<groupId>cn.itcast.demo</groupId>
<artifactId>feign-api</artifactId>
<version>1.0</version>
</dependency>