Spring Boot(3)EnableAutoConfiguration和EnableFeignClients实现

通过ImportSelector和@Import实现

以下以EnableAutoConfiguration为例说明各类Enable实现过程

ImportSelector说明

org.springframework.context.annotation.ImportSelector用于定义哪些被@Configuration 注解的类应该被导入。

public interface ImportSelector {

	/**
	 * 基于@Configuration 类的注解元数据判断类是否应该被导入、
	 * @return 返回需要被导入的@Configuration类的名称,如果为空数组表示没有需要导入的@Configuration类
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

	/**
	 * 返回一个predicate,predicate参数是selectImports发现需要导入的类名称
	 * 如果predicate返回true,则该类不会被导入
	 */
	@Nullable
	default Predicate<String> getExclusionFilter() {
		return null;
	}

}

ImportSelector的实现可以通过继承EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware接口或者单个构件赵晗,来获得以下对象实例

  • Environment
  • BeanFactory
  • ClassLoader
  • ResourceLoader

EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 
@AutoConfigurationPackage
// 注意:使用import注解导入ImportSelector实现类,来筛选Configuration
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

AutoConfigurationImportSelector

利用ImportSelector的实现类AutoConfigurationImportSelector,加载所需自动配置类

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
	
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		// 获取自动配置入口
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
				annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}
	
	// 获取自动配置入口
	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		// 读取jar包的META-INF/spring.factories文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration的属性值(配置了各个自动配置类名称)
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		// 进行去重、根据配置过滤不加载的自动配置类
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

通过ImportBeanDefinitionRegistrar和@Import实现

以下以EnableFeignClients为例说明

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {

	String[] value() default {};

	String[] basePackages() default {};

	Class<?>[] basePackageClasses() default {};

	Class<?>[] defaultConfiguration() default {};

	Class<?>[] clients() default {};
}

EnableFe通过@Import使用了FeignClientsRegistrar,它实现了org.springframework.context.annotation.ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar

public interface ImportBeanDefinitionRegistrar {

	/**
	 * 基于导入的类的注解元数据信息来注册Bean定义
	 */
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

}

同ImportSelector一样,其实现可以通过继承EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware接口或者单个构件赵晗,来获得以下对象实例

  • Environment
  • BeanFactory
  • ClassLoader
  • ResourceLoader

FeignClientsRegistrar

public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
		ResourceLoaderAware, BeanClassLoaderAware {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		// 获取EnableFeignClients注解的配置,并进行相应处理
		registerDefaultConfiguration(metadata, registry);
		// 注册所有FeignClient的Bean对象
		registerFeignClients(metadata, registry);
	}
	
	
	public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		ClassPathScanningCandidateComponentProvider scanner = getScanner();
		scanner.setResourceLoader(this.resourceLoader);

		Set<String> basePackages;

		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) {
		    // 未指定要扫描的有FeignClient类
		    
		    // 只扫描有FeignClient注解的类
			scanner.addIncludeFilter(annotationTypeFilter);
			// 根据EnableFeignClients注解配置的范围进行扫描
			basePackages = getBasePackages(metadata);
		}
		else {
			final Set<String> clientClasses = new HashSet<>();
			basePackages = new HashSet<>();
			for (Class<?> clazz : clients) {
				basePackages.add(ClassUtils.getPackageName(clazz));
				clientClasses.add(clazz.getCanonicalName());
			}
			AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
				@Override
				protected boolean match(ClassMetadata metadata) {
					String cleaned = metadata.getClassName().replaceAll("\\$", ".");
					return clientClasses.contains(cleaned);
				}
			};
			scanner.addIncludeFilter(
					new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
		}

		for (String basePackage : basePackages) {
		    // 从指定包下查找所有的候选类,并注册为Bean
			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();
					Assert.isTrue(annotationMetadata.isInterface(),
							"@FeignClient can only be specified on an interface");

					Map<String, Object> attributes = annotationMetadata
							.getAnnotationAttributes(
									FeignClient.class.getCanonicalName());

					String name = getClientName(attributes);
					registerClientConfiguration(registry, name,
							attributes.get("configuration"));

					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值