一、准备
@EnableFeignClients注解开启feign
@SpringBootApplication@EnableFeignClients//@RibbonClients 注意 配置类不能写在@SpringbootApplication注解的@CompentScan扫描得到的地方/*@RibbonClients(
value = {
@RibbonClient(name = "order-server",configuration = RuleConfig.class)
}
)*/publicclassUserApplication{publicstaticvoidmain(String[] args){
SpringApplication.run(UserApplication.class, args);}}
feigin接口上使用@FeignClient注解
//局部指定configuration 配置类FeignConfig,FeignConfig上不能有@Configuration注解,否则全局生效//@FeignClient(value = "order-server",path = "/order",configuration = FeignConfig.class)@FeignClient(value="order-server",path="/order")publicinterfaceOrderFeignService{/*@GetMapping("queryOrderByUserId/{userId}")
public String queryOrderByUserId(@PathVariable("userId") Long userId);*/@RequestLine("GET queryOrderByUserId/{userId}")public StringqueryOrderByUserId(@Param("userId") Long userId);}
二、源码分析
FeignAutoConfiguration自动配置类注入
@Configuration(proxyBeanMethods=false)@ConditionalOnClass(Feign.class)@EnableConfigurationProperties({ FeignClientProperties.class,
FeignHttpClientProperties.class})@Import(DefaultGzipDecoderConfiguration.class)publicclassFeignAutoConfiguration{@Autowired(required=false)private List<FeignClientSpecification> configurations=newArrayList<>();@Beanpublic HasFeaturesfeignFeature(){return HasFeatures.namedFeature("Feign", Feign.class);}//注入FeignContext@Beanpublic FeignContextfeignContext(){
FeignContext context=newFeignContext();
context.setConfigurations(this.configurations);return context;}@Configuration(proxyBeanMethods=false)@ConditionalOnClass(name="feign.hystrix.HystrixFeign")protectedstaticclassHystrixFeignTargeterConfiguration{//注入Targeter@Bean@ConditionalOnMissingBeanpublic TargeterfeignTargeter(){returnnewHystrixTargeter();}}@Configuration(proxyBeanMethods=false)@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")protectedstaticclassDefaultFeignTargeterConfiguration{@Bean@ConditionalOnMissingBeanpublic TargeterfeignTargeter(){returnnewDefaultTargeter();}}...}
FeignContext构造方法,设置FeignClientsConfiguration配置类,后面创建容器加载配置类:
publicFeignContext(){super(FeignClientsConfiguration.class,"feign","feign.client.name");}
FeignClientsConfiguration注入Decoder,Encoder,Contract等各种组件
@Configuration(proxyBeanMethods=false)publicclassFeignClientsConfiguration{@Autowiredprivate ObjectFactory<HttpMessageConverters> messageConverters;@Autowired(required=false)private List<AnnotatedParameterProcessor> parameterProcessors=newArrayList<>();@Autowired(required=false)private List<FeignFormatterRegistrar> feignFormatterRegistrars=newArrayList<>();@Autowired(required=false)private Logger logger;@Autowired(required=false)private SpringDataWebProperties springDataWebProperties;@Bean@ConditionalOnMissingBeanpublic DecoderfeignDecoder(){returnnewOptionalDecoder(newResponseEntityDecoder(newSpringDecoder(this.messageConverters)));}@Bean@ConditionalOnMissingBean@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")public EncoderfeignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider){returnspringEncoder(formWriterProvider);}@Bean@ConditionalOnClass(name="org.springframework.data.domain.Pageable")@ConditionalOnMissingBeanpublic EncoderfeignEncoderPageable(
ObjectProvider<AbstractFormWriter> formWriterProvider){
PageableSpringEncoder encoder=newPageableSpringEncoder(springEncoder(formWriterProvider));if(springDataWebProperties!= null){
encoder.setPageParameter(
springDataWebProperties.getPageable().getPageParameter());
encoder.setSizeParameter(
springDataWebProperties.getPageable().getSizeParameter());
encoder.setSortParameter(
springDataWebProperties.getSort().getSortParameter());}return encoder;}//SpringMVC注解它们是被谁处理的呢?//Contract的实现类SpringMVCContract就是来解析它们的,解析所有的注解信息、然后拼凑成一个完整的HTTP请求所需要的信息。@Bean@ConditionalOnMissingBeanpublic ContractfeignContract(ConversionService feignConversionService){returnnewSpringMvcContract(this.parameterProcessors, feignConversionService);}@Beanpublic FormattingConversionServicefeignConversionService(){
FormattingConversionService conversionService=newDefaultFormattingConversionService();for(FeignFormatterRegistrar feignFormatterRegistrar:this.feignFormatterRegistrars){
feignFormatterRegistrar.registerFormatters(conversionService);}return conversionService;}@Bean@ConditionalOnMissingBeanpublic RetryerfeignRetryer(){return Retryer.NEVER_RETRY;}@Bean@Scope("prototype")@ConditionalOnMissingBeanpublic Feign.BuilderfeignBuilder(Retryer retryer){return Feign.builder().retryer(retryer);}@Bean@ConditionalOnMissingBean(FeignLoggerFactory.class)public FeignLoggerFactoryfeignLoggerFactory(){returnnewDefaultFeignLoggerFactory(this.logger);}@Bean@ConditionalOnClass(name="org.springframework.data.domain.Page")public ModulepageJacksonModule(){returnnewPageJacksonModule();}@Bean@ConditionalOnClass(name="org.springframework.data.domain.Page")public ModulesortModule(){returnnewSortJacksonModule();}@Bean@ConditionalOnMissingBean(FeignClientConfigurer.class)public FeignClientConfigurerfeignClientConfigurer(){returnnewFeignClientConfigurer(){};}private EncoderspringEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider){
AbstractFormWriter formWriter= formWriterProvider.getIfAvailable();if(formWriter!= null){returnnewSpringEncoder(newSpringPojoFormEncoder(formWriter),this.messageConverters);}else{returnnewSpringEncoder(newSpringFormEncoder(),this.messageConverters);}}@Configuration(proxyBeanMethods=false)@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class})protectedstaticclassHystrixFeignConfiguration{@Bean@Scope("prototype")@ConditionalOnMissingBean@ConditionalOnProperty(name="feign.hystrix.enabled")public Feign.BuilderfeignHystrixBuilder(){return HystrixFeign.builder();}}privateclassSpringPojoFormEncoderextendsSpringFormEncoder{SpringPojoFormEncoder(AbstractFormWriter formWriter){super();
MultipartFormContentProcessor processor=(MultipartFormContentProcessor)getContentProcessor(
MULTIPART);
processor.addFirstWriter(formWriter);}}}
@EnableFeignClients注解开启feign
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(FeignClientsRegistrar.class)public @interfaceEnableFeignClients{...}
核心是@Import(FeignClientsRegistrar.class),FeignClientsRegistrar实现ImportBeanDefinitionRegistrar接口,注册bean定义时会调用registerBeanDefinitions方法
@OverridepublicvoidregisterBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry){//注册默认配置registerDefaultConfiguration(metadata, registry);//注册FeignClientsregisterFeignClients(metadata, registry);}
registerDefaultConfiguration注册默认配置
privatevoidregisterDefaultConfiguration(AnnotationMetadata metadata,
BeanDefinitionRegistry registry){//获得注解属性
Map<String, Object> defaultAttrs= metadata.getAnnotationAttributes(EnableFeignClients.class.getName(),true);if(defaultAttrs!= null&& defaultAttrs.containsKey("defaultConfiguration")){
String name;if(metadata.hasEnclosingClass()){
name="default."+ metadata.getEnclosingClassName();}else{
name="default."+ metadata.getClassName();}//name 是 default.com.xyy.UserApplication//注册Client配置类registerClientConfiguration(registry, name,
defaultAttrs.get("defaultConfiguration"));}}
registerClientConfiguration方法,向容器中注册BeanDefinition,类型是FeignClientSpecification
privatevoidregisterClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration){//注册一个FeignClientSpecification
BeanDefinitionBuilder builder= BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(
name+"."+ FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());}
下面看下registerFeignClients方法
publicvoidregisterFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry){//扫描器
ClassPathScanningCandidateComponentProvider scanner=getScanner();
scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;//获取@EnableFeignClients注解属性值
Map<String, Object> attrs= metadata.getAnnotationAttributes(EnableFeignClients.class.getName());//注解类型的过滤器AnnotationTypeFilter,指定注解是@FeignClient
AnnotationTypeFilter annotationTypeFilter=newAnnotationTypeFilter(
FeignClient.class);//获取@EnableFeignClients的clients属性final Class<?>[] clients= attrs== null? null:(Class<?>[]) attrs.get("clients");if(clients== null|| clients.length==0){//设置扫描器包含filter
scanner.addIncludeFilter(annotationTypeFilter);//获取扫描包,没设置的话,默认是有@EnableFeignClients注解类所在的包
basePackages=getBasePackages(metadata);}else{final Set<String> clientClasses=newHashSet<>();
basePackages=newHashSet<>();for(Class<?> clazz: clients){
basePackages.add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());}
AbstractClassTestingTypeFilter filter=newAbstractClassTestingTypeFilter(){@Overrideprotectedbooleanmatch(ClassMetadata metadata){
String cleaned= metadata.getClassName().replaceAll("\\$",".");return clientClasses.contains(cleaned);}};
scanner.addIncludeFilter(newAllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));}for(String basePackage: basePackages){//扫描组件
Set<BeanDefinition> candidateComponents= scanner.findCandidateComponents(basePackage);for(BeanDefinition candidateComponent: candidateComponents){if(candidateComponentinstanceofAnnotatedBeanDefinition){// verify annotated class is an interface
AnnotatedBeanDefinition beanDefinition=(AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata= beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(),"@FeignClient can only be specified on an interface");//获取@FeignClient注解的属性值
Map<String, Object> attributes= annotationMetadata.getAnnotationAttributes(
FeignClient.class.getCanonicalName());//获取Client名称
String name=getClientName(attributes);//如果有configuration属性,还要加载配置registerClientConfiguration(registry, name,
attributes.get("configuration"));//注册feginclientregisterFeignClient(registry, annotationMetadata, attributes);}}}}
getBasePackages方法:
protected Set<String>getBasePackages(AnnotationMetadata importingClassMetadata){
Map<String, Object> attributes= importingClassMetadata.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());//@EnableFeignClients 注解的value
Set<String> basePackages=newHashSet<>();for(String pkg:(String[]) attributes.get("value")){if(StringUtils.hasText(pkg)){
basePackages.add(pkg);}}//@EnableFeignClients 注解的basePackagesfor(String pkg:(String[]) attributes.get("basePackages")){if(StringUtils.hasText(pkg)){
basePackages.add(pkg);}}//@EnableFeignClients 注解的basePackageClassesfor(Class<?> clazz:(Class[]) attributes.get("basePackageClasses")){
basePackages.add(ClassUtils.getPackageName(clazz));}//以上都没有,则设为有@EnableFeignClients注解类所在的包if(basePackages.isEmpty()){
basePackages.add(
ClassUtils.getPackageName(importingClassMetadata.getClassName()));}return basePackages;}
registerFeignClient方法注册
privatevoidregisterFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes){//beaNname就是类名
String className= annotationMetadata.getClassName();//注册成FeignClientFactoryBean
BeanDefinitionBuilder definition= BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);validate(attributes);
definition.addPropertyValue(