一、前言
要讲清楚SpringBoot自动装配原理,我们可以分成两个问题进行讲解
1.什么时SpringBoot的自动装配
2.SpringBoot 是如何实现自动装配的?如何实现按需加载?
在学习Spring框架的时候,相信每个人脑海里都浮现过一句话:"要是有代码能够代替xml配置文件就好了!"
因为我们在引入某些功能的或者第三方依赖的时候,还需要显示配置XML和Java
像这样
Spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context/ http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc/ http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.howtodoinjava.demo" />
<mvc:annotation-driven />
<!-- JSON Support -->
<bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</beans>
@Configuration
public class RESTConfiguration
{
@Bean
public View jsonTemplate() {
MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setPrettyPrint(true);
return view;
}
@Bean
public ViewResolver viewResolver() {
return new BeanNameViewResolver();
}
}
终于,Springboot来了,SpringBoot我们只需添加相关的依赖,无需配置,通过启动主程序即可
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
并且,我们通过 Spring Boot 的全局配置文件 application.properties
或application.yml
即可对项目进行设置比如更换端口号,配置 JPA 属性等等。
为什么 Spring Boot 使用起来这么酸爽呢? 这得益于其自动装配。自动装配可以说是 Spring Boot 的核心,那究竟什么是自动装配呢?
二、什么是自动装配?
在Spring框架想使用redis的话,我们需要引入第三方依赖,需要手动配置非常麻烦,但是,在SpringBoot中,我们直接引入一个starter即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
我们进入SpringBoot父项目可以看到:
SpringBoot已经为我们配置了符合该版本的redis
所以什么是自动装配??
简单理解:通过注解或者一些简单的配置就能在Springboot 的帮助下实现某块功能
三、SpringBoot是如何实现自动装配的??
我们先看一下 SpringBoot 的核心注解 SpringBootApplication
。
大概可以把 @SpringBootApplication
看作是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类@ComponentScan
:扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描启动类同级及下级所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilter
和AutoConfigurationExcludeFilter
。
@EnableAutoConfiguration
是实现自动装配的重要注解,我们以这个注解入手。
EnableAutoConfiguration
只是一个简单地注解,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector
类。
那AutoConfigurationImportSelector
类做了些什么??
AutoConfigurationImportSelector
类继承体系如下:
可以看出,AutoConfigurationImportSelector
类实现了 ImportSelector
接口,也就实现了这个接口中的 selectImports
方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//判断自动装配开关是否打开、、、、、、
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
try {
//获取所有需要装配的Bean
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.<String>removeDuplicates(configurations);
configurations = this.sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return (String[])configurations.toArray(new String[configurations.size()]);
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
}
ok 现在我们可以打一个断点来debug一下看一看获取符合条件类的过程
到这一步可以看到, 共有96个配置内容被读取到了,但是这96个我们都用的到吗??继续向下执行
清除之后我们发现只剩下了20个符合条件的配置文件(或者说用得到的),因为我们在父项目中之引入了 start-web
除了这里我们还可以在 META-INF/spring.factories路径下观看被读取的配置文件