SpringBoot的自动装配原理(精髓所在)

SpringBoot是如何将相关组件装配到IOC的容器里面的?这个是核心的问题。

一、主启动类

/**
 * @author :breakpoint/赵立刚
 * @date : 2020/08/03
 */
@EnableAsync // 开启是否支持异步的操作
@SpringBootApplication // 声明当前的应用是SpringBoot的应用
public class StartMain {

    public static void main(String[] args) {
        SpringApplication.run(StartMain.class, args);
    }
}
二、@SpringBootApplication注解的功能
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // SpringBoot的配置 与 @Configuration的作用类似,都是可以自动发现配置的
@EnableAutoConfiguration // 开启自动的装配的工呢个
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
// 上面的 @ComponentScan 是包扫描方案,扫描哪些包
public @interface SpringBootApplication {

三、@EnableAutoConfiguration的功能

一共提供了@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)两个核心的注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
3.1 @AutoConfigurationPackage注解的功能

自动的配置我们的主启动类上面的包名

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

AutoConfigurationPackages.Registrar.class的主要的作用就是注册一个GenericBeanDefinition的bean的定义给IOC的容器。

将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;

3.2 AutoConfigurationImportSelector的功能

AutoConfigurationImportSelector:导入哪些组件的选择器;

将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;

会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件, 并配置好这些组件;

// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports
@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());
	}

接下来分析:getAutoConfigurationEntry方法

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
  // 获取到注解的属性信息
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
  // 获取到候选的配置信息,这一步也就是加载了所有的自动配置的信息,一会主要分析的就是这个方法
		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);
  // 首先获取到所有的配置的监听器,之后配置listener.onAutoConfigurationImportEvent(event);
		fireAutoConfigurationImportEvents(configurations, exclusions);
  //返回操作的对象
		return new AutoConfigurationEntry(configurations, exclusions);
	}
3.3 getCandidateConfigurations

这个是主要的返回我们候选配置类的基本信息:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  // 显然,和我们以前分析的一样,都是从META-INF/spring.factories获取到所有的EnableAutoConfiguration的组件并且进行返回。
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
  // 判断是否为空,默认肯定不是空的,因为spring-boot-autoconfigure-2.2.2.RELEASE.jar已经为我们配置了一些主要的的自动配置类。
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

四、如何将组件加入到IOC容器呢?

4.1 META-INF/spring.factories文件到底是什么样的

首先,在spring-boot-autoconfigure-2.2.2.RELEASE.jar里面,我们可以找到下面的文件

在这里插入图片描述

查看一下内容

# Auto Configure
# 可以看到一些自动配置的信息
# 全类名=自动配置类的集合
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
...
4.2 举例说明如何自动配置

我们用org.springframework.boot.autoconfigure.aop.AopAutoConfiguration为例子,来看一看如何的自动配置

// 说明当前是一个配置类
@Configuration(proxyBeanMethods = false)
// 判断当前是否配置了 spring.aop 的相关的配置
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

  
	@Configuration(proxyBeanMethods = false)
  // 当 Advice 存在的是欧,这个配置是生效的
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		static class CglibAutoProxyConfiguration {

		}

	}

	@Configuration(proxyBeanMethods = false)
  // 不存在 org.aspectj.weaver.Advice这个类,是生效的
	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	static class ClassProxyingConfiguration {

		ClassProxyingConfiguration(BeanFactory beanFactory) {
			if (beanFactory instanceof BeanDefinitionRegistry) {
				BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
		}

	}

}

通过上面的分析,其实我们可以发现,我们可以根据特定的环境分别的配置我们的组件,何时生效以及何时不生效,也就是这样,实现了SpringBoot的自动装配的最终的效果,实现了SpringBoot的精髓功能。

五、后记

@Conditional派生注解:

必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;

@Conditional扩展注解作用(判断是否满足当前指定条件)
@ConditionalOnJava系统的java版本是否符合要求
@ConditionalOnBean容器中存在指定Bean;
@ConditionalOnMissingBean容器中不存在指定Bean;
@ConditionalOnExpression满足SpEL表达式指定
@ConditionalOnClass系统中有指定的类
@ConditionalOnMissingClass系统中没有指定的类
@ConditionalOnSingleCandidate容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty系统中指定的属性是否有指定的值
@ConditionalOnResource类路径下是否存在指定资源文件
@ConditionalOnWebApplication当前是web环境
@ConditionalOnNotWebApplication当前不是web环境
@ConditionalOnJndiJNDI存在指定项
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值