Springboot的自动装配

@SpringBootApplication

在启动类中有@SpringBootApplication注解,点开@SpringBootApplication的源码我们发现
它是由多个注解组合成的一个注解,其中@SpringBootConfiguration也是个组合注解,表示该类为配置类
而@EnableAutoConfiguratio才是自动配置的核心注解

1
2
3
4
5
6
7
8
9
10
11
12
@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 {
///...代码省略

}

@EnableAutoConfiguratio

点开@EnableAutoConfiguration可以发现一个@Import注解,也就是说这里可以导入一个或多个配置类
接着在查看AutoConfigurationImportSelector.class

1
2
3
4
5
6
7
8
9
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
///...代码省略
}

AutoConfigurationImportSelector

可以发现他实现了一个DeferredImportSelector接口,而DeferredImportSelector接口继承了ImportSelector接口
这说明AutoConfigurationImportSelector是实现ImportSelector接口的类
也就是AutoConfigurationImportSelector可以通过selectImports方法返回多个配置类到@EnableAutoConfiguratio的@import注解中
在以下代码中可以看出返回值的数据源是通过getAutoConfigurationEntry方法获取的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
///...代码省略
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
///...代码省略
}

点开getAutoConfigurationEntry方法

getAutoConfigurationEntry是AutoConfigurationImportSelector中的方法
点开getCandidateConfigurations方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected AutoConfigurationEntry getAutoConfigurationEntry(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 = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

getCandidateConfigurations方法

getCandidateConfigurations是AutoConfigurationImportSelector中的方法
我们可以发现META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports的路径
也就是说selectImports方法返回值中的数据是来自AutoConfiguration.imports这个文件

1
2
3
4
5
6
7
8
9
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = new ArrayList<>(
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}

AutoConfiguration.imports

在AutoConfiguration.imports有许多自动配置类的全类名
我们拿DispatcherServletAutoConfiguration举例
DispatcherServletAutoConfiguration中通过注解可以发现他是个配置类,其中有一个注解是@ConditionalOnClass(DispatcherServlet.Class)也就是在当前环境中有DispatcherServlet的类该配置类生效
DispatcherServletAutoConfiguration中有个DispatcherServletConfiguration配置类,且该配置类中有一个dispatcherServlet方法,返回了一个dispatcherServlet类,并且该方法添加了@Bean从而生成了DispatcherServlet做到了自动配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
public class DispatcherServletAutoConfiguration {
///...代码省略
@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
protected static class DispatcherServletConfiguration {

@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
return dispatcherServlet;
}
///...代码省略
}
}

总结

这是图片

1.在主启动类上添加了SpringBootApplication注解,这个注解组合了EnableAutoConfiguration注解
2.EnableAutoConfiguration注解又组合了Import注解,导入了AutoConfigurationImportSelector类
3.实现selectImports方法,这个方法经过层层调用,最终会读取META-INF目录下的后缀名为Imports的文件,当然了,boot2.7以前的版本,读取的是spring.factories文件,
4.读取到全类名了之后,会解析注册条件,也就是@Conditional以及其衍生注解,把满足注册条件的Bean对象自动注入到Ioc容器中

自动装配的案例

准备一个jar包

这是图片

准备一个带@Bean的配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class MyConfig {
@Bean
@ConditionalOnClass(name="org.springframework.web.servlet.DispatcherServlet")
public Teacher getTeacher(){
return new Teacher();
}
@Bean
@ConditionalOnMissingBean(Teacher.class)
@ConfigurationProperties(prefix = "student")
public Student getStudent(){
return new Student();
}
}

准备一个自动配置类

1
2
3
4
5
6
@AutoConfiguration
@Import(MyConfig.class)
public class MyAutoConfig {
public MyAutoConfig(){
}
}

实体类

省略

在META-INF/spring/文件中创建org.springframework.boot.autoconfigure.AutoConfiguration.imports

将自动配置类的全类名添加到org.springframework.boot.autoconfigure.AutoConfiguration.imports中

打包成jar包

省略

将jar包保存到maven本地仓库

打开cmd输入
mvn install:install-file “-Dfile=C:\Users\23224\Desktop\demo16-0.0.1-SNAPSHOT.jar” “-DgroupId=demo16” “-DartifactId=reggie-demo16” “-Dversion=1.0” “-Dpackaging=jar”

导入依赖

1
2
3
4
5
<dependency>
<groupId>demo16</groupId>
<artifactId>reggie-demo16</artifactId>
<version>1.0</version>
</dependency>

在启动类中测试

1
2
3
4
5
6
7
8
@SpringBootApplication
public class Demo15Application {
public static void main(String[] args) {
ApplicationContext run = SpringApplication.run(Demo15Application.class, args);
Teacher bean = run.getBean(Teacher.class);
System.out.println(bean);
}
}