Loading

SpringBoot自动装配

什么是SpringBoot自动装配?

SpringBoot方便在于我们需要第三方依赖直接引入starter即可,通过少量的注解和一些简单的配置就能使用第三方组件的功能。SpringBoot的核心就在于自动装配,带来了极大地方便。

SpringBoot是如何自动装配?

SpringBoot 的核心注解 @SpringBootApplication

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};
	// 根据包路径扫描
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};
	// 直接根据class类扫描
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

	@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

@SpringBootApplication看作是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。

  • @Configuration:允许在上下文中注册额外的 bean 或导入其他配置类。
  • @EnableAutoConfiguration:代表开启springboot的自动装配。
  • @ComponentScan:自动扫描并加载符合条件的组件或bean定义,最终将这些bean定义加载到容器中。

关于@EnableAutoConfiguration实现自动装配注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//  加载自动装配类 xxxAutoconfiguration
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

        //按类型排序不需要自动装配的类
	Class<?>[] exclude() default {};

        //按名称排除不需要自动装配的类
	String[] excludeName() default {};

}

重点看看AutoConfigurationImportSelector 类做了什么

	private static final String[] NO_IMPORTS = {};
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
                 //  自动装配是否打开
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
                // 获取所有需要装配的bean
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

getAutoConfigurationEntry()方法主要负责加载自动配置类。

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
                // 1.判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
                // 2.用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName。
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
                // 3.获取需要自动装配的所有配置类,读取META-INF/spring.factories
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
                // 4.这一步有经历了一遍筛选,@ConditionalOnXXX 中的所有条件都满足,该类才会生效。
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}
  1. 判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置

  2. 用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName。

  3. 获取需要自动装配的所有配置类,读取META-INF/spring.factories

    从下图可以看到这个文件的配置内容都被我们读取到了。XXXAutoConfiguration的作用就是按需加载组件。

不光是这个依赖下的META-INF/spring.factories被读取到,所有 Spring Boot Starter 下的META-INF/spring.factories都会被读取到。
所以,你可以清楚滴看到, druid 数据库连接池的 Spring Boot Starter 就创建了META-INF/spring.factories文件。

  1. spring.factories中这么多配置,不是每次启动都要全部加载。
    经历了一遍筛选,@ConditionalOnXXX 中的所有条件都满足,该类才会生效。
posted @ 2021-09-10 15:16  在贝加尔湖畔  阅读(257)  评论(0编辑  收藏  举报