Spring Boot的自动装配机制?(Spring Boot怎么完成自动装配的?)
目录
一、概念版(重要)
二、实操版
1. 依赖管理 (pom.xml导坐标)
2. 自动配置类
2.1 @SpringBootApplication 注解
2.2 @EnableAutoConfiguration
2.3 @Import({AutoConfigurationImportSelector.class})
2.3.1 条件注解(Conditional Annotations)
2.4 META-INF/spring.factories 文件
一、概念版(重要)
答:自动装配,简单来说就是自动去把第三方组件的Bean转载到IOC容器中,不需要开发人员再去手写Bean相关的一个配置。在Spring Boot应用里面,只需要在启动类上加上@SpringBootApplication注解就可以去实现自动装配。@SpringBootApplication是一个复合注解,真正去实现自动配置的是@EnableAutoConfiguration注解。
自动装配主要依靠三个核心的关键技术。
第一个,引入Starter启动依赖组件的时候,这个组件里面必须要包含一个@Configuation配置类,而在这个配置类里面,我们要通过@Bean注解去声明需要装配到IOC容器里面的Bean对象。
第二个,这个配置类是放在第三方jar包里面的,然后通过Spring Boot中约定优于配置的理念去把这个配置类的全路径放在Classpath:/META-INF/spring.factories文件里面。这样的话,Spring Boot就可以知道第三方jar包里面这个配置类的位置。这个步骤主要是用到了Spring里面的SpringFactoriesLoader来完成的。
第三个,Spring Boot 获取到所有第三方 jar 包中声明的配置类以后,再通过Spring提供的ImportSelector这样一个接口,来实现对这些配置类的动态加载,从而去完成自动装配这样一个动作。
在我看来,Spring Boot是约定优于配置这一理念下的一个产物。所以在很多地方,都会看到这一类的思想,它的出现可以让开发人员更加聚焦的在业务代码的编写上,而不需要去关心和业务无关的配置。其实,自动装配的思想在SpringFramework 3.x版本里面的@Enable注解就已经有了实现的一个雏形。@Enable注解是一个模块驱动的意思,也就是说我们只需要增加@Enable注解就能自动打开某个功能,而不需要针对这个功能去做Bean的配置。@Enable注解的底层也是去帮我们自动完成这样一个模块相关Bean的注入的。
以上就是我对Spring Boot的自动装配的一个理解。
注:约定优于配置理念是什么?
约定优于配置(Convention Over Configuration) 是一种软件开发理念,指在软件开发中,遵循一些既定的约定和默认规则,从而减少开发人员需要进行的显式配置。
例如,在某些框架或技术中,可能会有以下的约定:
- 项目的目录结构:按照特定的层次结构存放代码、配置文件、资源文件等。
- 类和方法的命名规则:遵循一定的命名规范,以便框架能够自动识别和处理。
- 配置文件的默认位置和格式:框架会默认在特定的位置查找具有特定格式的配置文件。
通过遵循这些约定,开发人员无需花费大量时间和精力来详细配置每个细节,提高了开发效率,减少了配置错误的可能性,同时也使得代码和项目结构更加规范和易于理解。
以 Spring Boot 为例,如果遵循了其约定,比如将应用的配置文件命名为
application.properties
或application.yml
并放在特定的位置,框架就能自动识别并加载相应的配置,而无需开发人员显式地告诉框架配置文件的位置和名称。
二、实操版
Spring Boot 的自动配置(Auto-configuration)是其核心特性之一,它极大地简化了基于 Spring 的应用开发。 自动配置的工作原理主要依赖于“条件注解”(如
@Conditional
)和 Spring Factories(META-INF/spring.factories
文件)。以下是 Spring Boot 自动配置的基本步骤和原理:
1. 依赖管理 (pom.xml导坐标)
首先,需要添加spring-boot-starter-web
依赖,Spring Boot 就会自动配置 Tomcat 和 Spring MVC。
# pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
其次,在配置文件中写下Redis的配置就可以调用Redis的服务
2. 自动配置类
自动配置类通常使用 @Configuration
注解进行标注。在配置类中,可以通过 @Bean
方法定义要注入到 IOC 容器中的 Bean 对象。
例如:
2.1 @SpringBootApplication
注解
首先进入@SpringBootApplication注解的源代码:
@SpringBootApplication
是一个在 Spring Boot 项目中常用的复合注解。它组合了以下三个主要的注解功能:
@SpringBootConfiguration
:表明这是一个 Spring Boot 的配置类,继承自@Configuration
,用于定义 Bean 和配置相关的逻辑。
@EnableAutoConfiguration
:开启 Spring Boot 的自动配置功能。它会根据项目所依赖的库和配置来自动配置应用程序所需的各种组件和设置。
@ComponentScan
:用于扫描和注册项目中的组件(例如@Component
、@Service
、@Repository
等注解标注的类),使其能够被 Spring 容器管理。总的来说,使用
@SpringBootApplication
注解可以简化 Spring Boot 项目的配置,使开发更加便捷高效。通常将其添加在项目的主启动类上
例如:自动配置类
package com.apesource.springbootstarter04;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import redis.clients.jedis.Jedis;
@SpringBootApplication
public class SpringbootStarter04Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootStarter04Application.class, args);
Jedis bean1 = context.getBean(Jedis.class);
System.out.println(bean1);
}
}
2.2 @EnableAutoConfiguration
其次进入@EnableAutoConfiguration注解的源代码:
在Spring Boot 项目的主启动类上,通常会添加@
SpringBootApplication
注解。这是一个复合注解,其中关键的是 @EnableAutoConfiguration
注解,它开启了自动配置的功能。主要组合应用以下两个注解:
@AutoConfigurationPackage,将项目src中main包下的所有组件注册到容器中,例如标注了Component注解的类等等
@Import({AutoConfigurationImportSelector.class}),是自动装配的核心。 注解用于向 Spring 容器中导入指定的组件或配置类。
2.3 @Import({AutoConfigurationImportSelector.class})
选取部分 AutoConfigurationImportSelector类源代码:
AutoConfigurationImportSelector 是 Spring Boot 中一个重要的类,它实现了ImportSelector接口,用于实现自动配置的选择和导入。具体来说,它通过分析项目的类路径和条件来决定应该导入哪些自动配置类。主要工作是:
- 扫描类路径: 在应用程序启动时,AutoConfigurationImportSelector 会扫描类路径上的 META-INF/spring.factories 文件,这个文件中包含了各种 Spring 配置和扩展的定义。在这里,它会查找所有实现了 AutoConfiguration 接口的类,具体的实现为getCandidateConfigurations方法。
- 条件判断: 对于每一个发现的自动配置类,AutoConfigurationImportSelector 会使用条件判断机制(通常是通过 @ConditionalOnXxx 注解)来确定是否满足导入条件。这些条件可以是配置属性、类是否存在、Bean是否存在等等。
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
// ... (其他方法和属性)
// 获取所有符合条件的类的全限定类名,例如RedisTemplate的全限定类名(org.springframework.data.redis.core.RedisTemplate;),这些类需要被加载到 IoC 容器中。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 扫描类路径上的 META-INF/spring.factories 文件,获取所有实现了 AutoConfiguration 接口的自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 过滤掉不满足条件的自动配置类,比如一些自动装配类
configurations = filter(configurations, annotationMetadata, attributes);
// 排序自动配置类,根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序
sort(configurations, annotationMetadata, attributes);
// 将满足条件的自动配置类的类名数组返回,这些类将被导入到应用程序上下文中
return StringUtils.toStringArray(configurations);
}
// ... (其他方法)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 获取自动配置类的候选列表,从 META-INF/spring.factories 文件中读取
// 通过类加载器加载所有候选类
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
// 过滤出实现了 AutoConfiguration 接口的自动配置类
configurations = configurations.stream()
.filter(this::isEnabled)
.collect(Collectors.toList());
// 对于 Spring Boot 1.x 版本,还需要添加 spring-boot-autoconfigure 包中的自动配置类
// configurations.addAll(getAutoConfigEntry(getAutoConfigurationEntry(metadata)));
return configurations;
}
// ... (其他方法)
protected List<String> filter(List<String> configurations, AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 使用条件判断机制,过滤掉不满足条件的自动配置类
configurations = configurations.stream()
.filter(configuration -> isConfigurationCandidate(configuration, metadata, attributes))
.collect(Collectors.toList());
return configurations;
}
// ... (其他方法)
protected void sort(List<String> configurations, AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序对自动配置类进行排序
configurations.sort((o1, o2) -> {
int i1 = getAutoConfigurationOrder(o1, metadata, attributes);
int i2 = getAutoConfigurationOrder(o2, metadata, attributes);
return Integer.compare(i1, i2);
});
}
// ... (其他方法)
}
2.3.1 条件注解(Conditional Annotations)
Spring Boot 使用了一系列条件注解来决定是否应用特定的配置。例如:
@ConditionalOnClass
:只有当指定的类在类路径中存在时,才会激活相关配置。@ConditionalOnProperty
:根据配置文件中的属性值来决定是否应用配置。
例如:自定义主配置文件中RedisProperties文件必须存在才能执行
package com.apesource;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoconfiguration {
@Bean
public Jedis jedis(RedisProperties redisProperties){
return new Jedis(redisProperties.getHost(),redisProperties.getPort());
}
}
2.4 META-INF/spring.factories
文件
Spring Boot 会扫描项目及依赖的 JAR 包中的
META-INF\spring.factories
文件。这个文件中定义了自动配置类的全限定名,Spring Boot 可以根据这些信息找到并加载相应的配置类。
例如:resources\META-INF\spring.factories
# META-INF\spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.apesource.RedisAutoconfiguration
总的来说,Spring Boot 的自动装配机制通过依赖管理、注解、条件判断、配置类扫描和注册等一系列操作,实现了根据项目的具体情况自动完成组件的配置和加载。