Spring Boot的自动装配(Auto Configuration)是其核心特性之一,它允许开发者在项目中以最少的配置运行 Spring 应用。这一特性使得开发者无需手动配置大量的 Bean 和组件,Spring Boot 会根据项目中的依赖和应用场景,自动配置合适的 Spring 组件。
什么是自动装配?
未使用自动装配之前
在传统的 springmvc 项目中,当我们需要使用 mvc 模块、mysql 数据模块、redis 缓存模块的时候。我们需要导入依赖的 jar,然后在 spring 的配置文件中配置 dataSource
、sqlsessionFactory
、internalResourceViewResolver
(视图解析器)、multipartResolver
(文件上传)、事务管理器等模块。把这些我们需要的模块变成 bean,给 spring 管理。
SpringBoot
定义了一套接口规范,这套规范规定:SpringBoot
在启动时会扫描外部引用 jar 包中的META-INF/spring.factories
文件,将文件中配置的类型信息加载到 Spring
容器(此处涉及到 JVM
类加载机制与 Spring
的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot
定义的标准,就能将自己的功能装置进 SpringBoot
。
在了解自动装配之前,我们首先来回顾一下以前的 springMVC
项目。在 MVC
中我们使用容器依赖的bean
的时候需要在 xml
中配置声明才能使用,比如 springmvc
中的以下配置。
在web.xml
中配置 dispatcherServlet
和 filter
没用使用自动装配之前,这些庞杂的web配置是每一个项目必须的。我们首先在pom中引入相关的jar。然后再xml中一遍一遍的配置这些东西。 十分复杂低效。
初步了解自动装配
springboot 是一个脚手架工具,约定大于配置。我们只需要按照 springboot 的规范来开发,就能减少很多配置,当需要开发 web 项目的时候。
第一步:引入web 包的 starter 启动器。这个包就包含了 web 的所需的主要功能,同时能导入springweb 相关的依赖 jar。比如spring,springmvc 的包和 tomcat 的包。点击 pom 可查询。
<!--springboot的web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
第二步: 我们启动springboot项目之后,就能看到所有的bean。这些bean在容器加载的时候就会把bean自动加载进来。
@SpringBootApplication(scanBasePackages = "com.thits")
@ImportResource(value = "bean.xml") //装配xml文件配置的bean
public class SpringBoot1Application {
public static void main(String[] args) {
//返回ioc容器
ConfigurableApplicationContext run = SpringApplication.run(SpringBoot1Application.class, args);
//获取容器中的所有bean
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("bean的名字:"+beanDefinitionName);
}
}
}
截图可以看到控制台的各种 bean 已经被 spring 容器管理了。 比如 multipartResolver
、DispatcherServlet
、视图解析器、事务管理器等。我们就可以直接使用了,不需要在 xml 中配置这些东西了。
自动装配、按需加载
在启动类中有一个注解就是 @SpringBootApplication
,他有三个子注解,子注解又有其他的注解,搞清楚这些注解的意思就能理解自动装配了。
Spring Boot应用程序的入口通常带有@SpringBootApplication
注解。这个注解是一个组合注解,包含了@Configuration
、@EnableAutoConfiguration
和@ComponentScan
。
@SpringBootApplication
(有三个子注解)@SpringBootConfiguration
@Configuaration
@EnableAutoConfiguration
(开启自动注入:有两个子注解)@AutoConfigurationPackage
(自动配置包:有一个子注解,import)@Import({Registrar.class})
@Import({AutoConfigurationImportSelector.class})
@ComponentScan
(组件扫描 作用:包扫描项目包路径)
其中,@EnableAutoConfiguration
是自动装配的关键,它启动了自动装配机制。
@Import({Registrar.class})
注解的源码
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
@Import({Registrar.class})
源码的作用就是:主启动类注册到容器,也就是 main
方法所在的包下边,将所有的我们自己的代码中的配置注入的 bean
容器。
通过实现 ImportBeanDefinitionRegistrar
,向 Spring
容器中添加 Bean
定义
@Import({AutoConfigurationImportSelector.class})
注解的源码
源码的第一步就是实现 ImportSelector
接口的 ImportSelector
方法,根据类的全部限定名字把类注入到容器(参见 import
注解的用法),注入了那些类呢?接着看源码
此处源码是获取自动装配的配置类。获取了138个,在哪里获取接着看。
这里的代码就能看出来去哪里加载了这些自动装配的类,在factories文件中。
我们查看 autoconfigure
的 jar 下边的 factories
文件就能看到这些指定的自动装配类全类名了。
自动装配含义
通过@SpringBootApplication注解的两个Import子注解 ,把spring-boot-autoconfigure-2.6.7.jar和其他包的spring.factories 文件中,EnableAutoConfiguration配置的所有类都装配到spring容器中了。
自动装配扩展原理(Condition按需加载)
springboot自动装配的扩展:两个疑难问题讲解:
问题1:
我们查看spring.factories中有当前版本支持的所有配置类,这些配置类都会注入bean吗?
答:并不是,之后我们需要导入相对的jar包,这个类是真是存在的,然后才可以自动装配这些bean。
举例说明:在spring.factories中有很多配置类,我们截取这几个来说明
举例1:我们没有配置 DispatcherServlet
,但是会通过自动装配,层层判断来自动创建出DispatcherServlet
举例2:我们Aop的案例
问题2
在spring 的 IOC 注入了这些138个配置类,我们怎么使用?
答:通过配置使用,约定大约配置。
比如我们使用文件上传。我们怎么知道配置文件上传的文件大小、文件路径等信息。在源码中我们可以看到怎么使用。约定大于配置
springboot默认创建StandardServletMultipartResolver,在源码中如下
文件上传约定大约配置,我们都知道 ConfigurationProperties
注解的作用是绑定配置文件的值。这里就是约定大于配置。我们只需要按照约定来就行了
自动装配总结:
1:springboot
默认加载 spring.factories
中指定的所有 AutoConfiguration
。
2:根据这些 AutoConfiguration
的源码,在里边的条件 @conditional
判断是否真正的使用这些类。
3:导入的对应 jar
话就使用这些类,并且在绑定的 Properties
根据前缀中指定,然后在配置文件中配置属性
这就是自动装配了。