SpringBoot自动配置原理

1、按住Ctrl点击查看启动类SpringbootTestApplication 上的注解@SpringBootApplication
@SpringBootApplication()
public class SpringbootTestApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootTestApplication.class, args);
    }
}
2.注解@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 {

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

发现@SpringBootApplication其实是一个组合注解,这里重点的注解有3个:

  • @SpringBootConfiguration:是一个配置类
  • @EnableAutoConfiguration:开启自动配置
  • @ComponentScan:开启注解扫描
3.分析@SpringBootConfiguration注解

按Ctrl点击查看SpringBootConfiguration注解的源码:
在这里插入图片描述
通过源码可以看到,这个注解的上面有一个@Configuration注解,接着阅读该注解的注释,我们可以知道:

  • 这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration的类,并且读取其中的配置信息。而@SpringBootConfiguration是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。
4.分析@ComponentScan注解

@ComponentScan注解是Spring的一个注解,用于组件扫描,这是注解方式的扫描,还有xml方式的扫描:<context:component-scan />指定扫描的包。
我们跟进去查看该注解的注释:
在这里插入图片描述
大概的意思:

  • 配置组件扫描的指令。提供了类似与<context:component-scan>标签的作用。
  • 通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包。

我们知道@ComponentScan注解声明是在main方法所在的启动类上,所以扫描的包是启动类所在的包及子包,所以我们应该把启动类放在项目中包比较浅的目录中。

5.分析@EnableAutoConfiguration注解

按住Ctrl点击查看注解@EnableAutoConfiguration:
在这里插入图片描述
通过源码可以看到@EnableAutoConfiguration注解上有@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)两个注解,接着阅读该注释,我们大致知道该注解的作用:

  • 开启spring应用程序的自动配置,SpringBoot基于你所添加的依赖和你自己定义的bean,试图去猜测并配置你想要的配置。比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcat、SpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!
  • SpringBoot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效(条件注解是否生效)。

即每一个xxxAutoConfiguration都有条件注解,标注该配置类是否生效,是否采用默认配置,或者自定义配置,条件注解一般有:

  • @ConditionalOnClass : classpath中存在该类时起效
  • @ConditionalOnMissingClass : classpath中不存在该类时起效
  • @ConditionalOnBean : DI容器中存在该类型Bean时起效
  • @ConditionalOnMissingBean : DI容器中不存在该类型Bean时起效
  • @ConditionalOnSingleCandidate : DI容器中该类型Bean只有一个或@Primary的只有一个时起效
  • @ConditionalOnExpression : SpEL表达式结果为true时
  • @ConditionalOnProperty : 参数设置或者值一致时起效
  • @ConditionalOnResource : 指定的文件存在时起效
  • @ConditionalOnJndi : 指定的JNDI存在时起效
  • @ConditionalOnJava : 指定的Java版本存在时起效
  • @ConditionalOnWebApplication : Web应用环境下起效
  • @ConditionalOnNotWebApplication : 非Web应用环境下起效
5.1分析@AutoConfigurationPackage注解

按住Ctrl点击查看注解@AutoConfigurationPackage的源码:

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

}

该注解的作用:添加该注解的类所在的package 作为 自动配置package 进行管理。

@ComponentScan和@EnableAutoConfiguration的区别:
参考:https://blog.csdn.net/wangbiao007/article/details/101020426

5.2分析@Import(AutoConfigurationImportSelector.class)

按住ctrl点击查看@Import注解的作用:

  1. 导入@Configuration注解的配置类(4.2 版本之前只可以导入配置类,4.2版本之后 也可以导入 普通类)
  2. 导入ImportSelector的实现类
  3. 导入ImportBeanDefinitionRegistrar的实现类

它提供了与springxml中的<import/>元素等效的功能。

按住Ctrl点击查看AutoConfigurationImportSelector这个类,发现:
在这里插入图片描述
发现AutoConfigurationImportSelector实现了DeferredImportSelector接口,DeferredImportSelector接口又继承了ImportSelector接口,所以@Import(AutoConfigurationImportSelector.class)导入ImportSelector的实现类,就是@Import作用的第2种。
当项目启动时,Spring容器会实例化AutoConfigurationImportSelector类,并且调用selectImports方法,我们看下selectImports方法的源码:
在这里插入图片描述
可以看到最后一个方法的异常信息,其中,SpringFactoriesLoader.loadFactoryNames 方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表。
在这里插入图片描述
spring.factories 文件中有关自动配置的配置信息如下:

........
# 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,\
.......

上面配置文件存在大量的以Configuration为结尾的类名称,这些类就是存有自动配置信息的类,而SpringApplication在获取这些类名后再加载。只要有任意一个配置类被加载,整个文件就会被加载,并且缓存起来,下次从缓存中拿。
我们在加读取全部配置类后,会进行过滤,去掉没用到的、没生效的、用户自定义的配置类。

6、加载配置类

我们以ServletWebServerFactoryAutoConfiguration配置类为例,进行源码分析:

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
//........
}

其中:
@EnableConfigurationProperties(ServerProperties.class)代表加载ServerProperties服务配置属性类,声明要使用ServerProperties配置类的对象,进入ServerProperties.class源码如下:

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

	/**
	 * Server HTTP port.
	 */
	private Integer port;

	/**
	 * Network address to which the server should bind.
	 */
	private InetAddress address;
	//.......
}

其中prefix代表SpringBoot配置文件中属性的前缀,SpringBoot会将配置文件中该前缀的属性映射到类中的属性,进行数据绑定。
映射关系如下:
在这里插入图片描述
SpringBoot是基于约定大于配置,所以很多配置都有默认值,每一个自动配置类结合对应的 xxxProperties.java 读取配置文件进行自动配置功能,我们可以在application.yml或application.properties中覆盖这些配置。

面试被问及SpringBoot的自动装配原理怎么说?

springboot通过main方法启动,在main方法中会调用run方法,在run方法执行的时候,会有刷新容器的过程,就是refreshContext(context),在刷新容器的时候就会解析注解,将我们的Bean注入到容器中,这时就会解析启动类上的@SpringBootApplication注解,这个注解是个组合注解,下面说一下这个组合注解的3个比较重要的注解及作用,@SpringBootConfiguration注解,表示启动类是一个SpringBoot配置类,@ComponentScan注解,进行组件扫描,默认是扫描该启动类所在的包及其子包,还有@EnableAutoConfiguration注解,开启自动装配,这个注解里Import了一个类,当项目启动时,spring会实例化这个类,并调用其中的selectImports方法,这个方法会帮我们加载类路径下的META-INF/spring.factories文件,这个文件中有很多的配置类,配置类上会有很多的条件注解,会根据你引入的jar包,或者其他条件进行过滤排除一些配置类,然后把相应的Bean注入到容器里边,从而实现了自动装配。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值