依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
开关
使用feign调用
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 {
/* 原本的get请求是: http://userservice/user/id
* 现在使用 feign来发送请求 就是这样的 */
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
改造代码
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.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private UserClient userClient;
// @Autowired
// private RestTemplate restTemplate;
// public Order queryOrderById(Long orderId) {
// // 1.查询订单
// Order order = orderMapper.findById(orderId);
//
// String url = "http://userservice/user/" + order.getUserId();
//
// User user = restTemplate.getForObject(url, User.class);
//
// order.setUser(user);
//
// // 4.返回
// return order;
// }
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
User user = userClient.findById(order.getUserId());
order.setUser(user);
// 4.返回
return order;
}
}
feign自动实现负载均衡
之前使用 restTemplate的时候 需要配加入注解 @LoadBalanced 才会被 ribbon拦截,才能够负载均衡,
而现在直接使用 feign 直接就能够做负载均衡,因为 feign的内部集成了 ribbon
修改配置
日志级别
在order的配置文件之内声明
feign:
client:
config:
default: #如果是 default 就是全局 如果是 userservice的话 就是只针对这个服务
loggerLevel: FULL # 还可以设置成 NONE BASIC
Feign的优化
Feign其实只是将请求变成 地址,最终发送请求的 其实还是其他的一些组件
默认使用的是 jdk自带的 URLConnection
那么既然要使用 apache httpclient ,就需要引入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
然后开启 httpclient
feign:
httpclient:
enabled: true
max-connections: 200
max-connections-per-route: 50
client:
config:
default:
loggerLevel: BASIC
Feign的常用实践方式
就之前的代码结构来说 order 里面调用 user里面的方法 ,那么返回的数据的类型一般都是 user类型,所以说 ,如果要在 order里面 接收 user类型的对象,需要在 order的实体类里面也创建一个 和User类型一摸一样的实体类 。设想一下,一个项目一般来说都会有很多很多的实体类,如果有多个服务之间来回调用,那么就会导致大量的实体类的代码重复,解决方式就是 将这些是实体类抽取出来
既然实体类抽取了出来,那么我们还可以进一步的去抽取一些共用的东西, 比如 接口 , feign的配置
所以我们这样做:
单独建立一个模块,里面有 所有的实体类,接口 以及feign的配置文件。
当然,关于feign的依赖 也需要在这个模块中引入
那么现在order只需要引入这个模块即可,
并且,之前的一些关于 feign的依赖都可以注释掉了,order里面的实体类也去除了,接口也去除了
但是这样会导致一个问题;
如下图
order-service 模块启动的时候,会扫描其下的包,并创建对象,当他扫描到 自动注入接口对象的时候(也就是这里的userClient),本来应该自动注入对象,但是spring并不能在容器中找到这个对象,但是这里又没有报错 为什么?
编译没有报错证明这个类 的确找到了 但是无法注入成功,因为在spring容器中找不到他,也就是压根就没有创建出来对象,也就是说 没有扫描到依赖中的那个 UserClient 接口,没有扫描到,自然不会创建对象
所以说需要
指定包的位置
这里为什么需要这样,这里涉及到另外一个知识点:在引入依赖的时候 会有 xxx-xxx-starter 的形式,还有的依赖是没有 starter依赖的,带有 starter的依赖包都会有 如下文件
里面的内容为:
# Auto Configure
org.springframework.boot.env.EnvironmentPostProcessor=\
com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration,\
com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\
com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
意思就是说,把里面的包,拼接到 项目的主启动类的 @ComponentScan里面
如果没有这个文件,springboot是不会对这个依赖里面的东西进行扫描的
所以说:springboot在启动的时候会 扫描同级别的包和其下的包,以及依赖。这个说法并不是非常准确,需要有 xx.factories文件以及实现一个类(这个类具体是什么本人还没学习到),这样才会在项目启动的时候帮你扫描包
不然无法解释
- spring 扫描主启动类下的包 以及 依赖 并创建对象放入容器