Feign源码分析

2022-07-28 09:56:49

一、准备

@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(
  • 作者:小相公爱玩
  • 原文链接:https://blog.csdn.net/u010342147/article/details/123669493
    更新时间:2022-07-28 09:56:49