前言
Feign 是一个声明式的 web service 客户端。Spring Cloud 中的 Open Feign 在 Feign 的基础上支持 Spring MVC 注解、JAX-RS 注解,同时集成了 Ribbon、Eureka(对于负载均衡,同样支持 Spring Cloud LoadBalancer)
对 @EnableFeignClients 注解进行解析,扫描指定路径下的所有标注 @FeignClient 注解的接口,解析其标注的 @FeignClient 注解,然后生成动态代理。最后组装成一个 Request 对象,进行远程通信。
代码样例
方式一 、服务提供者模块定义 Feign Client 接口
order-api模块
@RequestMapping("order")
public interface OrderService {
@GetMapping("orders")
String orders();
}
@FeignClient("spring-cloud-order")
public interface OrderServiceFeignClient extends OrderService {
}
order-application模块
@RestController
public class OrderServiceImpl implements OrderService {
@Value("${server.port}")
private Integer port;
@Override
public String orders() {
return String.valueOf(port);
}
}
server:
port: 8081
spring:
application:
name: spring-cloud-order
server:
port: 8082
spring:
application:
name: spring-cloud-order
user-service模块
@RestController
public class UserController {
@Autowired
private OrderServiceFeignClient orderServiceFeignClient;
@GetMapping("user2")
public String user2() {
return orderServiceFeignClient.orders();
}
}
@SpringBootApplication
@EnableFeignClients(basePackages = {
"com.mzs.order.api.clients"
})
public class SpringCloudUserApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudUserApplication.class, args);
}
}
方式二 、在服务消费者模块定义 Feign Client 接口
order-api模块
public interface OrderService {
String orders();
}
order-service模块
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("orders")
public String orders() {
return orderService.orders();
}
}
server:
port: 8081
spring:
application:
name: spring-cloud-order
server:
port: 8082
spring:
application:
name: spring-cloud-order
user-service模块
@FeignClient("spring-cloud-order")
@RequestMapping("order")
public interface OrderServiceFeignClient {
@GetMapping("orders")
String orders();
}
spring-cloud-order:
ribbon:
listOfServers: localhost:8081,localhost:8082
@RestController
public class UserController {
@Autowired
private OrderServiceFeignClient orderServiceFeignClient;
@GetMapping("user2")
public String user2() {
return orderServiceFeignClient.orders();
}
}
@SpringBootApplication
@EnableFeignClients
public class SpringCloudUserApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudUserApplication.class, args);
}
}
源码分析
一、@EnableFeignClients
用于扫描所有标注 @FeignClient注解的接口。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
......
}
二、FeignClientsRegistrar
FeignClientsRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,看下 registerBeanDefitions(…) 方法的具体实现,如下:
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 注册 @EnableFeignClients 注解 defaultConfiguration 属性指定的配置类
registerDefaultConfiguration(metadata, registry);
// 获取 @FeignClient 注解的属性以及属性值,填充到 FeignClientFactoryBean
// 从而注册到 IOC 容器中
registerFeignClients(metadata, registry);
}
1、registerDefaultConfiguration(…) 方法
private void registerDefaultConfiguration(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 获取 @EnableFeignClients 注解的属性以及属性值
Map<String, Object> defaultAttrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
// 如果 @EnableFeignClients 注解有指定 defaultConfiguration 属性
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
}
else {
name = "default." + metadata.getClassName();
}
// 注册指定的配置类
registerClientConfiguration(registry, name,
defaultAttrs.get("defaultConfiguration"));
}
}
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
// 创建关于FeignClientSpecification的BeanDefinitionBuilder实例
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
// 将@EnableFeignClients 注解 defaultConfiguration 属性指定的配置类封装到 FeignClientSpecification
builder.addConstructorArgValue(configuration);
// 注册到 IOC 容器中
registry.registerBeanDefinition(
name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
2、registerFeignClients(…) 方法
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
// 获取 @EnableFeignClients 注解的属性以及属性值
Map<String, Object> attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
final Class<?>[