2、根据@FeignClient生成代理类

1、开启FeignClient功能

我们在 app-b应用的主启动类AppBMain 上有个 @EnableFeignClients 注解,我们知道注解 @Enablexxxx 开启xxx功能,一般在这类的注解上都有@Import的注解,同样 EnableFeignClients 注解上也有。

@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
	......
}

@EnableFeignClients意思就是 “开启FeignClient功能”,其本质就是在Spring容器中注册一些Bean的定义,后续根据这些定义实例化这些Bean,这些Bean实例提供了FeignClient的功能。

在这里插入图片描述

我们列出了简略的代码如下:

Spring容器会顺着启动类AppBMain(也是配置类),扫描到其 @Import 的类 FeignClientsRegistrar,然后使用反射对其实例化,调用栈如下

addImportBeanDefinitionRegistrar:199, ConfigurationClass (o.s.context.annotation)
// ^将FeignClientsRegistrar实例放入容器中(一个配置文件对应一个)
processImports:604, ConfigurationClassParser (o.s.context.annotation)
// ^实例化@import注解导入的类FeignClientsRegistrar(@Import(FeignClientsRegistrar.class)),并将其放入容器
// 导入的类型分三种:1、ImportSelector(会递归处理);2、ImportBeanDefinitionRegistrar;3、其他(当做配置类来处理)
doProcessConfigurationClass:304, ConfigurationClassParser (o.s.context.annotation)
processConfigurationClass:247, ConfigurationClassParser (o.s.context.annotation)
// ^处理解析出来的的配置类
parse:200, ConfigurationClassParser (o.s.context.annotation)
// ^为每个配置类创建一个ConfigurationClass实例
// 并放入ConfigurationClassParser实例的Map<ConfigurationClass, ConfigurationClass>类型的属性中
parse:169, ConfigurationClassParser (o.s.context.annotation)
// ^解析配置类
processConfigBeanDefinitions:308, ConfigurationClassPostProcessor (o.s.context.annotation)
// ^找出配置类
postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (o.s.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (o.s.context.support)
invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (o.s.context.support)
invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (o.s.context.support)
refresh:525, AbstractApplicationContext (o.s.context.support)
refresh:122, EmbeddedWebApplicationContext (o.s.boot.context.embedded)
refresh:693, SpringApplication (o.s.boot)
refreshContext:360, SpringApplication (o.s.boot)
run:303, SpringApplication (o.s.boot)
run:1118, SpringApplication (o.s.boot)
run:1107, SpringApplication (o.s.boot)
main:15, AppBMain (com.yh.stu)

从调用栈中processConfigBeanDefinitions:308看出,调用栈中 processImports:604,ConfigurationClassParser ,就在这个方法中,实例化所有@import的类

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
	......
	processImports(configClass, sourceClass, getImports(sourceClass), true);
	......
}
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
	Set<SourceClass> imports = new LinkedHashSet<SourceClass>();
	Set<SourceClass> visited = new LinkedHashSet<SourceClass>();
	collectImports(sourceClass, imports, visited);
	return imports;
}
// 递归调用来查找@import注解标注的 SourceClass
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
			throws IOException {
	if (visited.add(sourceClass)) {
		for (SourceClass annotation : sourceClass.getAnnotations()) {
			String annName = annotation.getMetadata().getClassName();
			if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
				//递归调用
				collectImports(annotation, imports, visited);
			}
		}
		imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
	}
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
	......
		for (SourceClass candidate : importCandidates) {
			if (candidate.isAssignable(ImportSelector.class)) {
				......					
			}
			else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
				// Candidate class is an ImportBeanDefinitionRegistrar ->
				// delegate to it to register additional bean definitions
				Class<?> candidateClass = candidate.loadClass();
				ImportBeanDefinitionRegistrar registrar =
						BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
				ParserStrategyUtils.invokeAwareMethods(
						registrar, this.environment, this.resourceLoader, this.registry);
				configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
			}
			else {
				......
			}
		}
	......
}

调用其实现ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法,在这个方法中注册Feign功能需要的bean的定义到容器中。

Spring Boot的启动类 AppBMain 为什么是配置类? 因为其标注的@SpringBootApplication 间接标注了 @Configuration,而 Spring是循环递归扫描的注解的,所以Spring 认为 AppBMain 也是个配置类。

下面是我debug时候的调用栈,大家看看注释里的解释

registerFeignClient:176, FeignClientsRegistrar (o.s.cloud.netflix.feign)
registerFeignClients:167, FeignClientsRegistrar (o.s.cloud.netflix.feign)
registerBeanDefinitions:92, FeignClientsRegistrar (o.s.cloud.netflix.feign)
// 调用ImportBeanDefinitionRegistrar的registerBeanDefinitions方法,这里通常就是用来注册bean的定义的
loadBeanDefinitionsFromRegistrars:360, ConfigurationClassBeanDefinitionReader (o.s.context.annotation)
// 从容器中 ImportBeanDefinitionRegistrar实例中加载bean定义
loadBeanDefinitionsForConfigurationClass:144, ConfigurationClassBeanDefinitionReader (o.s.context.annotation)
// ^加载配置文件中的bean定义,注:可以将ImportBeanDefinitionRegistrar的实例看做bean的定义,实例里本来就是用来定义了一些bean
loadBeanDefinitions:116, ConfigurationClassBeanDefinitionReader (o.s.context.annotation)
// 使用ConfigurationClassBeanDefinitionReader 来解析配置并注册bean定义
processConfigBeanDefinitions:320, ConfigurationClassPostProcessor (o.s.context.annotation)
postProcessBeanDefinitionRegistry:228, ConfigurationClassPostProcessor (o.s.context.annotation)
// ConfigurationClassPostProcessor 循环递归解析配置并注册bean定义
invokeBeanDefinitionRegistryPostProcessors:272, PostProcessorRegistrationDelegate (o.s.context.support)
// 调用容器中的所有的BeanDefinitionRegistryPostProcessor
invokeBeanFactoryPostProcessors:92, PostProcessorRegistrationDelegate (o.s.context.support)
invokeBeanFactoryPostProcessors:687, AbstractApplicationContext (o.s.context.support)
refresh:525, AbstractApplicationContext (o.s.context.support)
refresh:122, EmbeddedWebApplicationContext (o.s.boot.context.embedded)
refresh:693, SpringApplication (o.s.boot)
refreshContext:360, SpringApplication (o.s.boot)
run:303, SpringApplication (o.s.boot)
run:1118, SpringApplication (o.s.boot)
run:1107, SpringApplication (o.s.boot)
main:15, AppBMain (com.yh.stu)

2、FeignClientsRegistrar注册FeignClientFactoryBean

FeignClientsRegistrar类实现了一些接口(代码如下),这些接口的作用属于Spring Framework的知识。

class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
		ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
	.......		
}

ℹ️​ Spring Framwork 知识- ImportBeanDefinitionRegistrar 接口
在容器启动过程的中,会调用后置处理器阶段会调用容器中所有类型为 ImportBeanDefinitionRegistrar 类型的实例的 registerBeanDefinitions(...) 方法,该方法向容器中注册Bean 的定义,这些Bean的定义在Bean的实例化时需要使用。(解析出配置的所有配置类中配置的Bean的定义,包括@Import标注的类中定义的Bean)。
在refresh的 invokeBeanFactoryPostProcessors(beanFactory) 方法中,会调用“配置类后置处理器”(ConfigurationClassPostProcessor)来解析Spring应用的配置。这个“配置类后置处理器”是Spring Framework 容器创建的阶段就注册进容器了(不是refresh阶段)。

ImportBeanDefinitionRegistrar 类型的Bean就是在这个阶段实例化并调用的。

	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		registerDefaultConfiguration(metadata, registry);
		registerFeignClients(metadata, registry);
	}
	public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		ClassPathScanningCandidateComponentProvider scanner = getScanner();
		scanner.setResourceLoader(this.resourceLoader);
		Set<String> basePackages;
		// metadata就是主启动类上的注解元数据
		Map<String, Object> attrs = metadata
				.getAnnotationAttributes(EnableFeignClients.class.getName());
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
				FeignClient.class);
		final Class<?>[] clients = attrs == null ? null
				: (Class<?>[]) attrs.get("clients");
		if (clients == null || clients.length == 0) {
			scanner.addIncludeFilter(annotationTypeFilter);//添加FeignClient注解的过滤
			basePackages = getBasePackages(metadata);
		}else {
			......
		}
		for (String basePackage : basePackages) {
			//查找包下所有标注@FeignClient的类
			Set<BeanDefinition> candidateComponents = scanner
					.findCandidateComponents(basePackage);
			for (BeanDefinition candidateComponent : candidateComponents) {
				if (candidateComponent instanceof AnnotatedBeanDefinition) {
					// verify annotated class is an interface
					AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
					AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
					.......
					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}
	private void registerFeignClient(BeanDefinitionRegistry registry,
			AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		String className = annotationMetadata.getClassName();
		BeanDefinitionBuilder definition = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientFactoryBean.class);
		validate(attributes);
		.......
		definition.addPropertyValue("name", name);// app-a
		definition.addPropertyValue("type", className);
		.......
		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
				new String[] { alias });
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
	}
	......

3、调用FeignClientFactoryBean的getObject

FeignClientsRegistrar注册了FeignClientFactoryBean的BD后,

@Override
public Object getObject() throws Exception {
	FeignContext context = applicationContext.getBean(FeignContext.class);
	Feign.Builder builder = feign(context);
	if (!StringUtils.hasText(this.url)) {
		String url;
		if (!this.name.startsWith("http")) {
			url = "http://" + this.name;
		}
		else {
			url = this.name;
		}
		url += cleanPath();
		return loadBalance(builder, context, new HardCodedTarget<>(this.type,
				this.name, url));
	}
	if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
		this.url = "http://" + this.url;
	}
	// 如果你在@FeignClient上,没有配置url属性,也就是你没有自己指定服务的url地址,那么就会自动跟ribbon关联起来,
	// 采用ribbon来进行负载均衡,直接就开始为ribbon来准备对应的url地址了
	String url = this.url + cleanPath();
	Client client = getOptional(context, Client.class);
	if (client != null) {
		if (client instanceof LoadBalancerFeignClient) {
			// not lod balancing because we have a url,
			// but ribbon is on the classpath, so unwrap
			client = ((LoadBalancerFeignClient)client).getDelegate();
		}
		builder.client(client);
	}
	Targeter targeter = get(context, Targeter.class);
	return targeter.target(this, builder, context, new HardCodedTarget<>(
			this.type, this.name, url));
}
protected Feign.Builder feign(FeignContext context) {
	// 这里为app-a 创建了一个ApplicationContext
	FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
	Logger logger = loggerFactory.create(this.type);

	// @formatter:off
	Feign.Builder builder = get(context, Feign.Builder.class)
			// required values
			.logger(logger)
			.encoder(get(context, Encoder.class))
			.decoder(get(context, Decoder.class))
			.contract(get(context, Contract.class));
	// @formatter:on

	configureFeign(context, builder);

	return builder;
}

protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
		HardCodedTarget<T> target) {
	Client client = getOptional(context, Client.class);
	if (client != null) {
		builder.client(client);
		Targeter targeter = get(context, Targeter.class);
		return targeter.target(this, builder, context, target);
	}
	
	throw new IllegalStateException(
			"No Feign Client for loadBalancing defined. Did you forget to include 
			spring-cloud-starter-netflix-ribbon?");
}

1、applicationContext.getBean(FeignContext.class) 调用栈:

<init>:31, FeignContext (o.s.cloud.netflix.feign)
feignContext:72, FeignAutoConfiguration (o.s.cloud.netflix.feign)
CGLIB$feignContext$1:-1, FeignAutoConfiguration$$EnhancerBySpringCGLIB$$c4e49129 
(o.s.cloud.netflix.feign)
invoke:-1, FeignAutoConfiguration$$EnhancerBySpringCGLIB$$c4e49129
$$FastClassBySpringCGLIB$$55cd8dc9 (o.s.cloud.netflix.feign)invokeSuper:228, MethodProxy (o.s.cglib.proxy)
intercept:358, ConfigurationClassEnhancer$BeanMethodInterceptor (o.s.context.annotation)
feignContext:-1, FeignAutoConfiguration$$EnhancerBySpringCGLIB$$c4e49129 (o.s.cloud.netflix.feign)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
instantiate:162, SimpleInstantiationStrategy (o.s.beans.factory.support)
// ^ 反射调用return factoryMethod.invoke(factoryBean, args);这里的factoryBean是CGLIB代理类:
// FeignAutoConfiguration$$EnhancerBySpringCGLIB$$c4e49129
instantiateUsingFactoryMethod:588, ConstructorResolver (o.s.beans.factory.support)
instantiateUsingFactoryMethod:1181, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
createBeanInstance:1075, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
doCreateBean:513, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
createBean:483, AbstractAutowireCapableBeanFactory (o.s.beans.factory.support)
getObject:312, AbstractBeanFactory$1 (o.s.beans.factory.support)
getSingleton:230, DefaultSingletonBeanRegistry (o.s.beans.factory.support)
doGetBean:308, AbstractBeanFactory (o.s.beans.factory.support)
getBean:220, AbstractBeanFactory (o.s.beans.factory.support)
resolveNamedBean:1018, DefaultListableBeanFactory (o.s.beans.factory.support)
getBean:345, DefaultListableBeanFactory (o.s.beans.factory.support)
getBean:340, DefaultListableBeanFactory (o.s.beans.factory.support)
getBean:1092, AbstractApplicationContext (o.s.context.support)
getObject:220, FeignClientFactoryBean (o.s.cloud.netflix.feign)
----------------------......
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java硕哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值