Spring Boot(十一)自动装配原理解析

SpringBoot框架使用好几年了,都晓得5分钟搭建一个项目,方便快捷,但是却并没有总结过为啥会这么快捷呢?他到底是如何自动装配的呢?
先看看SpringBoot的主配置类:

@SpringBootApplication(scanBasePackages = {"com.huohuo.info"})
public class Bootstrap {

	public static void main(String[] args) {
		SpringApplication.run(Bootstrap.class, args);
	}


}

main方法启动,运行run方法,传入一个被@SpringBootApplication注解的类。

一、整体图解

来看一个简单的概要图:
在这里插入图片描述
@SpringBootApplication点进去能看到是一个组合注解:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

二、@SpringBootConfiguration

在这里插入图片描述
在这里插入图片描述
通过源码得知,@SpringBootConfiguration其实就是想表达我是一个配置值类,和配置文件一样。表面翻译也就是SpringBoot的配置

三、@EnableAutoConfiguration

顾名思义,这个注解一定和自动配置相关。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

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

    String[] excludeName() default {};
}

1)@AutoConfigurationPackage

在这里插入图片描述
这个注解是自动配置包,主要是使用的@Import来给Spring容器中导入一个组件 ,这里导入的是Registrar.class。
在这里插入图片描述
我们可以看到Registrar是一个静态内部类,获取扫描的包路径。debug调试可以看一下。
(PS:右键通过Evaluate Expression窗口,输入红色标记信息,查看想看的值)可以看到,我们获取到了包路径信息
在这里插入图片描述
metadata参数到底是什么呢?我们通过调试看到,其实就是标记在最开始项目标记的包路径,也就是主配置类。

在这里插入图片描述
在这里插入图片描述
说白了理解就是将主配置类所在包及子包里面所有组件扫描加载到Spring容器。所以包名一定要注意。

2)@Import({AutoConfigurationImportSelector.class})

@AutoConfigurationPackage注解实现了包扫描路径,那具体加载哪些组件呢?
@Import注解就是给Spring容器中导入一些组件,这里传入了一个组件的选择器:AutoConfigurationImportSelector。
AutoConfigurationImportSelector实现了DeferredImportSelector。Spring内部在解析@Import时会调用getAutoConfigurationEntry方法,扫描具有META-INF/spring.factories文件的jar包。

 protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            /* 从META-INF/spring.factories中获取候选的自动配置类*/
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            /*排重*/
            configurations = this.removeDuplicates(configurations);
            /*根据EnableAutoConfiguration注解中属性,获取不需要自动装配的类名单*/
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            /*根据@EnableAutoConfiguration.exclude
            @EnableAutoConfiguration.excludeName
            spring.autoconfigure.exclude进行排除*/
            this.checkExcludedClasses(configurations, exclusions);
            /*exclusions也排除*/
            configurations.removeAll(exclusions);
            /*通过读取spring.factories中的OnBeanCondition\OnClassCondition\OnWebApplicationCondition进行过滤*/   
            configurations = this.filter(configurations, autoConfigurationMetadata);
           
           /*这个方法是调用实现了AutoConfigurationImportListener的bean.分别把候选的配置名单,和排除的配置名单传进去做扩展*/
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

看getCandidateConfigurations,获取候选的配置

/*获得候选的配置*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        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;
    }

实际上它返回了一个List,这个List是由loadFactoryNames()方法返回的,其中传入了一个getSpringFactoriesLoaderFactoryClass(),我们可以看看这个方法的内容。

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }

我们看到了一个眼熟的词 —— EnableAutoConfiguration,也就是说,它实际上返回的就是标注了这个类的所有包。标注了这个类的包不就是@SpringBootApplication吗!
再看还有一个断言:意思是,configurations必须非空,否则就打印一段话,No auto configuration classes found in META-INF/spring.factories。
通过断点调试,我们会发现加载了119个配置类,实际上并非全部会使用。
在这里插入图片描述
过滤掉之后还剩31个生效的
在这里插入图片描述
简单理解:来来回回,兜兜转转绕了这么多地方,又回到了EnableAutoConfiguration身上,其实就是为了将启动类所需的所有资源导入,需要啥生效啥。

3)自动配置生效

@ConditionalOnBean:当容器里存在指定bean的条件下。
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
@ConditionalOnClass:当类路径下有指定类的条件下。
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

4)mybatis自动配置

以mybatis为例来看一下:
在这里插入图片描述

任何一个springboot应用,都会引入spring-boot-autoconfigure,而spring.factories文件就在该包下面。spring.factories文件是Key=Value形式,多个Value时使用,隔开,该文件中定义了关于初始化,监听器等信息,这是Spring的SPI机制。真正使自动配置生效的key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,看如下mybatis的spring.factories文件内容

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnBean({DataSource.class})
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MybatisAutoConfiguration {
  • @Configuration,表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件。
  • @ConditionalOnClass 判断当前项目有没有这个类,这个类需要在classpath中有SqlSessionFactory和SqlSessionFactoryBean定义时才会起效,并且要有一个DataSource的candidate注册到spring容器中
  • @ConditionalOnBean 必须存在DataSource信息源
  • @EnableConfigurationProperties将配置文件中对应的值和 MybatisProperties绑定起来;并把 MybatisProperties加入到 IOC 容器中。并注册ConfigurationPropertiesBindingPostProcessor用于将@ConfigurationProperties的类和配置进行绑定。

四、@ComponentScan

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值