SpringBoot自动配置原理
1 SpringBoot自动配置思想
-
自动配置说到底就是为了加速开发的效率,将开发者在开发过程中,用到的某种技术所需要的bean提前加载好。
-
使用bean的时候,如果不设置属性,就有默认值;如果不想用默认值,就可以自己设置,也就是可以修改部分或者全部参数。
即,一些技术的某些参数或属性,SpringBoot无法自动配置,我们可以自行配置(在application.properties
中配置(或application.yaml
))。
比如要用mysql技术,导入了mysql的坐标,springboot就知道了你要做数据库操作,一系列的数据库操作相关的bean都给你提前声明好,但是你要告诉springboot你到底用哪一个数据库,像什么IP地址
啊,端口
啊,你不告诉spirngboot,springboot就无法帮你把自动配置相关的工作做完。
所以,当我们想使用某项技术,且不需要自己设置参数时,只需要:引入一个组件(该技术)依赖(导入组件坐标)即可。
如果想修改该技术的相关参数,则
- 引入一个组件依赖(导入组件坐标)
- 加配置
下面举个例子。
1.1 在项目中使用redis数据库
- 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 编写配置
spring:
redis:
database: 0
timeout: 5000ms
host: 127.0.0.1
port: 6379
password: 123456
好了,接下来只需要使用时注入RedisTemplate对象
就能使用了:
@Autowired
private RedisTemplate redisTemplate;
这期间,我们做了什么嘛?我们什么也没有做。
那么,这个RedisTemplate对象
是怎么注入到Spring容器中的呢?
2. SpringBoot自动配置原理
总的来说就一句话:springboot
启动时,会扫描外部引用jar
包(External Libraries
)中的META-INF/spring.factories
文件,加载spring.factories
文件中的org.springframework.boot.autoconfigure.EnableAutoConfiguration
配置项,将其中配置的所有的类都加载成bean
,加载到spring容器,并执行相应类中定义的各种骚操作。
再简洁一点:通过某种方式读取spring.factories
文件,紧接着把里面所有的自动配置类加载到Spring
容器中,然后就可以通过Spring
的机制将配置类的@Bean
注入到容器中了。
再如上述的redis例子,我们引入了redis依赖(spring-boot-starter-data-redis
),那么在外部引用jar
包(External Libraries
)中,redis的相关META-INF/spring.factories
文件也会被spring boot自动扫描到,并进行自动配置,RedisTemplate对象
被放入spring
容器。
3 如何读取spring.factories文件?
- @SpringBootApplication
- @EnableAutoConfiguration
- AutoConfigurationImportSelector
- 实现ImportSelector接口,重写了selectImports方法(该方法获取所有符合条件的类的全限定类名),有了类的全限定类名,可以通过反射机制,将类的对象bean加载到spring容器。
- 具体地,selectImports方法实现4中的逻辑,是依靠
getAutoConfigurationEntry
方法。
更具体的,请看:
看完就会的SpringBoot自动装配原理
Spring Boot 自动装配原理
4 变更自动配置
知道了自动配置的执行过程,下面就可以根据这个自动配置的流程做一些高级定制了。例如系统默认会加载100多种自动配置的技术,如果我们先手工干预此工程,禁用自动配置是否可行呢?答案一定是可以的。方式还挺多:
方式一:通过yaml配置设置排除指定的自动配置类
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
方式二:通过注解参数排除自动配置类
@EnableAutoConfiguration(excludeName = "",exclude = {})
方式三:排除坐标(应用面较窄)
如果当前自动配置中包含有更多的自动配置功能,也就是一个套娃的效果。此时可以通过检测条件的控制来管理自动配置是否启动。例如web程序启动时会自动启动tomcat服务器,可以通过排除坐标的方式,让加载tomcat服务器的条件失效。不过需要提醒一点,你把tomcat排除掉,记得再加一种可以运行的服务器。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--web起步依赖环境中,排除Tomcat起步依赖,匹配自动配置条件-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加Jetty起步依赖,匹配自动配置条件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
</dependencies>
总结
- springboot的自动配置并不是必然运行的,可以通过配置的形式干预是否启用对应的自动配置功能