主启动类注解
@SpringBootApplication 是 Spring Boot 应用的核心注解,通常用于标注主启动类。
@SpringBootApplication 主要是由三个注解组合而成:
@SpringBootConfiguration:本质上是@Configuration注解,它允许在上下文中注册额外的 bean 或导入其他配置类。@EnableAutoConfiguration:读取META-INF/spring.factories文件,加载里面预定义的配置类。@ComponentScan:扫描当前启动类所在的包以及该包下的所有子包,寻找带有@Component、@Controller、@Service、@Respository、@Configuration等注解的类,并将它们注册到 Spring 容器中。
Bean 管理
Bean 注册
对于可以直接修改源码的项目,可使用以下构造型注解标记类,使类能够被 Spring 发现并注册到 IoC 容器中:
@Component:通用注解。@Respository:持久层注解。@Service:服务层注解。@Controller:控制层注解,返回视图名称。@RestController:控制层注解,相当于@Controller+@ResponseBody,将返回值自动序列化(JSON 或者 XML)写入 HTTP 响应体。
依赖注入
@Autowired- 是 Spring 的原生注解。
- 可以修饰在字段、构造器、setter方法、方法参数上。
- 在匹配时先看类型,如果匹配上了多个 Bean,就再根据名字进行匹配。
- 使用
@Autowired+@Qualifier可以匹配指定名字的 Bean 。 - 在定义 Bean 的地方添加
@Primary可以让这个 Bean 优先被匹配。
@Resource- 是 Java 标准的注解。
- 可以修饰在字段、setter方法上。
- 在匹配时先看名字,如果指定了
name属性,那么找不到就直接报错。如果没有指定name属性,那么找不到就再按照类型进行匹配。
Bean 作用域
在定义 Bean 的位置使用 @Scope("scopeName") 注解可以定义 Bean 的作用域,常见的作用域包括:
singleton:整个 IoC 容器共享一个 Bean。prototype:每次获取容器都会创建一个全新的 Bean。request(仅 Web 应用可用):HTTP 请求开始时创建 Bean,HTTP 请求结束后销毁 Bean。session(仅 Web 应用可用):用户首次访问时创建 Bean,session 过期或注销时销毁 Bean。application(仅 Web 应用可用):整个 Web 应用共享一个 Bean。websocket(仅 Web 应用可用):websocket 连接建立时创建 Bean,连接断开时销毁 Bean。
配置
声明配置类
@Configuration用于标注 Spring 的配置类。@Configuration可以扫描且识别内部的@Bean方法,但是它与@Component的区别在于代理机制。@Configuration标注的类会由 Spring 通过 CGLIB 生成动态代理子类。这个代理的作用是拦截@Bean方法的调用:它会先检查 IoC 容器中是否已存在该对象,如果有则直接返回单例,否则才创建新对象。这确保了在配置类内部进行方法间调用时,依然能获取到容器管理的单例 Bean。- 相比之下,
@Component标注的类没有这种代理机制。在其内部直接调用另一个@Bean方法等同于普通的 Java 方法调用,会导致重复创建对象。因此,在@Component中,必须通过将依赖 Bean 作为方法参数传入的方式来正确注入依赖。
@Import注解必须写在带有@Configuration的类上。
读取配置信息
@Value 注入
@Value 用于注入比较简单的配置信息,一般情况下不建议使用这种注入方式。
@RestControllerpublic class StudentController { @Value("${profile.age}") private int age;
@Value("${profile.name}") private String name;}@ConfigurationProperties 注入
@ConfigurationProperties 可以实现更加复杂的配置信息注入:
@Component@ConfigurationProperties(prefix = "library")@Datapublic class LibraryProperties { // 绑定规则非常宽松 // 如果 Java 字段是 bookName // 则配置文件可匹配的字段有:book_name/book-name/BOOK_NAME private String location;
private List<Book> books;}
@RestController@RequestMapping("/library")public class BookController { private LibraryProperties libraryProperties;
public BookController(LibraryProperties libraryProperties) { this.libraryProperties = libraryProperties; }}TIP除了使用
@Component注解, 还可以通过以下方式进行注册 ConfigurationProperties(注意不能使用多种方式重复注册):
@Import(XXX.class):语意不清,不推荐。@EnableConfigurationProperties(XXX.class):含义清晰,能结合 SpringBoot 自动装配机制,推荐使用。@ConfigurationPropertiesScan("com.example.xxx"):批量导入指定包的 ConfigurationProperties。
加载自定义配置文件
@PropertySource 可以指定需要加载哪个自定义配置文件中的配置信息。需要注意的是,这种方式只能加载 .properties 文件,对于 yml 文件需要进行更复杂的处理。
@Configuration// 核心:加载 classpath 下的 custom.properties 文件// encoding = "UTF-8" 非常重要!否则中文会乱码// value 可以为数组@PropertySource(value = "classpath:custom.properties", encoding = "UTF-8")public class MyConfig {
// 加载进来后,就可以用 @Value 读取了 @Value("${my.app.name}") private String appName;
public void print() { System.out.println("加载到的应用名:" + appName); }}MVC
映射 HTTP 请求
GET 请求
// @RequestMapping(value = "/user", method = RequestMethod.GET)@GetMapping("/user")public Result<List<User>> getAllUsers() { return Result.success(userService.list());}POST 请求
// @RequestMapping(value = "/user", method = RequestMethod.POST)@PostMapping("/user")public Result<Integer> createUser(@Valid @RequestBody UserCreateRequest userCreateRequest) { return Result.success(userService.save());}PUT 请求
// @RequestMapping(value = "/user/{userId}", method = RequestMethod.PUT)@PutMapping("/user/{userId}")public Result<Void> updateUser(@PathVariable Long userId,@Valid @RequestBody UserUpdateRequest userUpdateRequest) { return Result.success();}DELETE 请求
// @RequestMapping(value = "/user/{userId}, method = RequestMethod.DELETE")@DeleteMapping("/user/{userId}")public Result<Void> deleteUser(@PathVariable Long userId) { return Result.success();}PATCH 请求
// @RequestMapping(value = "/user/{userId}", method = RequestMethod.PATCH)@PatchMapping("/user/{userId}")public Result<Void> updateUser(@PathVariable Long userId,@Valid @RequestBody UserUpdateRequest userUpdateRequest) { return Result.success();}绑定参数
从 URL 路径中提取参数
@PathVariable 用于从 URL 路径中提取参数:
@DeleteMapping("/user/{userId}")public Result<Void> deleteUser(@PathVariable("userId") Long userId) { return Result.success();}TIP
- 当模版里的名字与参数名字一致时,可以只写
@PathVariable。- 也可以像示例那样显式指定模版里的名字。
绑定查询参数
@RequestParam 用于绑定查询参数:
@GetMapping("/user")public Result<List<User>> getUserByAge(@RequestParam("age") Integer age) { return Result.success(userService.listByAge(age));}TIP
- 当参数名和 URL 中的 key 相同时,可以直接省略注解。
- 标准写法是像示例那样显式指定 key 的名称。
- 如果参数是可选的,可以指定默认值
@Request(value = "age", defaultValue = 18),或者是直接让参数值为空@Request(value = "age", isRequired = false)。
绑定请求体中的 JSON 数据
@RequestBody 可以将 Content-Type 为 application/json 的 Request 的请求体解析成 Java 对象:
@PostMapping("/user")public Result<User> createUser(@Valid @RequestBody UserCreateRequest userCreateRequest) { return Result.success(userService.save());}数据校验
引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId></dependency>校验注解
@Null:被注释的元素必须为 null。@NotNull:被注释的元素必须不为 null。@AssertTrue:被注释的元素必须为 true。@AssertFalse:被注释的元素必须为 false。@Min(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值。@Max(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值。@DecimalMin(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值。@DecimalMax(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值。@Size(max=, min=):被注释的元素的大小必须在指定的范围内。@Digits(integer=, fraction=):被注释的元素必须是一个数字,其整数位数和小数位数必须在可接受的范围内。@Past:被注释的元素必须是一个过去的日期。@Future:被注释的元素必须是一个将来的日期。@Pattern(regex=,flag=):被注释的元素必须符合指定的正则表达式。
校验请求体
对于请求体的校验只需要在对应方法参数前添加 @Valid 注解即可:
@Data@AllArgsConstructor@NoArgsConstructorpublic class Person { @NotNull(message = "classId 不能为空") private String classId;
@Size(max = 33) @NotNull(message = "name 不能为空") private String name;
@Pattern(regexp = "((^Man$|^Woman$|^UGM$))", message = "sex 值不在可选范围") @NotNull(message = "sex 不能为空") private String sex;
@Email(message = "email 格式不正确") @NotNull(message = "email 不能为空") private String email;}
@RestController@RequestMapping("/api")public class PersonController { @PostMapping("/person") public Result<Person> getPerson(@RequestBody @Valid Person person) { return Result.ok(person); }}校验路径参数及请求参数
对于路径参数和请求参数这种普通方法参数的校验,则需要先在类上添加 @Validated 注解,让 Spring 启用对这个类的参数校验,然后在方法参数前加上对应的校验注解:
@RestController@RequestMapping("/api")@Validatedpublic class PersonController {
@GetMapping("/person/{id}") public Result<Integer> getPersonByID( @PathVariable("id") @Max(value = 5, message = "ID 不能超过 5") Integer id ) { return Result.ok(id); }
@GetMapping("/person") public Result<String> findPersonByName( @RequestParam("name") @NotBlank(message = "姓名不能为空") @Size(max = 10, message = "姓名长度不能超过 10") String name ) { return Result.ok("Find the person : " + name); }}全局异常处理
首先定义错误码接口,错误码由 code、message、status组成:
public interface IErrorCode { int getCode();
HttpStatus getStatus();
String getMessage();}每个模块都要实现自己的错误码接口,这里以通用错误码为例:
@Getter@AllArgsConstructorpublic enum ErrorCode implements IErrorCode {
RESOURCE_NOT_FOUND(1001, "未找到该资源", HttpStatus.NOT_FOUND), REQUEST_VALIDATION_FAILED(1002, "请求数据格式验证失败", HttpStatus.BAD_REQUEST), SYSTEM_ERROR(5000, "系统繁忙,请稍后重试", HttpStatus.INTERNAL_SERVER_ERROR);
private final int code;
private final String message;
private final HttpStatus status;}然后实现基类异常,它由错误码和负载数据组成:
@Getterpublic abstract class BaseException extends RuntimeException { private final ErrorCode errorCode;
private final Map<String, Object> data = new HashMap<>();
// 带数据的构造方法 protected BaseException(ErrorCode errorCode, Map<String, Object> data) { super(errorCode.getMessage()); this.errorCode = errorCode; if (!ObjectUtils.isEmpty(data)) { this.data.putAll(data); } }
// 不带数据的构造方法 protected BaseException(ErrorCode errorCode) { super(errorCode.getMessage()); this.errorCode = errorCode; }}具体的业务异常,可以考虑提供更加友好的构造方法:
public class ResourceNotFoundException extends BaseException { public ResourceNotFoundException() { super(ErrorCode.RESOURCE_NOT_FOUND); }
public ResourceNotFoundException(Map<String, Object> data) { super(ErrorCode.RESOURCE_NOT_FOUND, data); }}接下来实现相应结果类,响应结果包括 code、message、status、data、path、timestamp ,只有操作失败才会返回 path :
@Datapublic class Result<T> { private int code;
private String message;
private int status;
private T data;
private Instant timestamp;
private String path;
private Result() { this.timestamp = Instant.now(); }
public static <T> Result<T> success(T data) { return Result.success(data, "操作成功"); }
public static <T> Result<T> success(T data, String message) { Result<T> result = new Result<>(); result.setCode(200); result.setMessage(message); result.setData(data); result.setStatus(HttpStatus.OK.value()); return result; }
public static Result<Map<String, Object>> failure(IErrorCode errorCode, String path, Map<String, Object> data) { Result<Map<String, Object>> result = new Result<>(); result.setCode(errorCode.getCode()); result.setMessage(errorCode.getMessage()); result.setStatus(errorCode.getStatus().value()); result.setData(data); result.setPath(path); return result; }}最后定义全局异常处理器:
// @RestControllerAdvice = @ResponseBody + @ControllerAdvice// 使用 value = {xxx.class, yyy.class} 可以只处理指定类抛出的异常@RestControllerAdvice@Slf4jpublic class GlobalExceptionHandler { // 指定方法要捕获的异常字节码,匹配范围越小的匹配优先级越高 @ExceptionHandler(value = BaseException.class) public Result<Map<String, Object>> handleBaseException(BaseException e, HttpServletRequest request) { log.warn( "Business exception | code={} | message={} | status={} | data={} | path={}", e.getErrorCode().getCode(), e.getErrorCode().getMessage(), e.getErrorCode().getStatus(), e.getData(), request.getRequestURI() ); return Result.failure(e.getErrorCode(), request.getRequestURI(), e.getData() ); }
@ExceptionHandler(value = Exception.class) public Result<Map<String, Object>> handleException(Exception e, HttpServletRequest request) { log.error( "System exception | path={} | message={}", request.getRequestURI(), e.getMessage(), e ); return Result.failure( ErrorCode.SYSTEM_ERROR, request.getRequestURI(), null ); }}事务
事务管理方式
- 编程式事务管理:通过
TransactionTemplate或者TransactionManager手动管理事务,实际应用中很少使用。 - 声明式事务管理:使用
@Transactional注解管理事务,推荐使用。
事务属性详解
事务传播行为
@Transactional(propagation=Propagation.取值):
- 加入当前事务
REQUIRED(默认):- 当前有事务,则加入当前事务。
- 当前没有事务,则开启一个新事务。
SUPPORTS:- 当前有事务,则加入当前事务。
- 当前没有事务,则在无事务的状态下执行。
MANDATORY:- 当前有事务,则加入当前事务。
- 当前没有事务,抛出异常。
- 不加入当前事务
REQUIRED_NEW:- 当前有事务,则挂起当前事务,同时开启一个新事务。
- 当前没有事务,则直接开启一个新事务。
NOT_SUPPORTED:- 当前有事务,则挂起当前事务,在没有事务的状态下执行。
- 当前没有事务,则直接在没有事务的状态下执行。
NEVER:- 当前有事务,抛出异常。
- 当前没有事务,则在没有事务的状态下执行。
NESTED:- 当前有事务,则开启当前事务的子事务。
- 当前没有事务,则开启一个新事务。
NOTE
REQUIRED_NEW和NESTED的区别主要在于:前者在方法执行完毕时就提交事务了,而后者需要在主事务执行完毕时才能提交事务。
事务隔离级别
@Transactional(isolation=Isolation.取值):
DEFAULT:数据库设置的默认隔离级别。READ_UNCOMMITTED:读未提交。READ_COMMITTED:读已提交。REPEATABLE_READ:可重复读。SERIALIZABLE:串行化。
事务超时属性
@Transactional(timeout=123):以秒为单位,默认值是-1,表示不指定超时时间。
事务只读属性
@Transactional(readOnly = true):建议在一次需要执行多个查询语句的时候开启,这样这些查询语句可以共用一个读快照,不会出现数据不一致的问题。
事务回滚规则
@Transactional(rollbackFor = Exception.class):指定遇到什么异常会触发事务回滚,默认值是 RuntimeException.class,一般需要指定为 Exception.class 以保证所有异常都要触发回滚。
事务使用注意事项
@Transactional注解只有作用到 public 方法上事务才生效。- 不推荐在接口上使用
@Transactional,因为只有 JDK 代理会识别这个注解,有兼容问题。 - 避免同一个类中调用
@Transactional注解的方法,这样会导致事务失效。 - 被
@Transactional注解的方法所在的类必须被 Spring 管理,否则不生效。 - 底层使用的数据库必须支持事务机制,否则不生效。
@Transactional:可以标记在类上,也可以标记在方法上,如果同时标记在类上和方法上,则以方法上的注解为准。
核心概念
IoC
描述
IoC 指的是控制反转,它将创建管理对象的权利交给第三方容器。在传统的写法里,一个对象使用另一个对象时要自己手动 new,自己来管理依赖。而使用 IoC,只需要描述自己需要什么,IoC 容器会将对象自动装配好。
优势
- 显著降低了对象之间的耦合度。
- 使对象资源更加容易创建并管理。
AOP
基本理解
AOP 即面向切面编程。它最大的作用其实就是解耦。我们在写代码的时候经常会遇到一种情况,就是像记录日志、权限校验这些逻辑,它们其实跟具体的业务没啥关系,但又必须得写,而且很多方法里都要写,这就很麻烦,代码也很乱。所以 AOP 就是为了解决这个问题的。它能把这些杂活单独抽出来,封装成一个切面,然后动态地织入到业务逻辑里。这样业务代码就干净了,只关注业务逻辑本身。从底层原理来看,AOP 是基于动态代理实现的。在 Spring 中,如果类实现了接口,用的是 JDK 动态代理,否则使用 CGLIB 动态代理。在 SpringBoot 2.0 之前,默认使用 JDK 动态代理。在 SpringBoot 2.0 之后,默认使用 CGLIB 动态代理。
核心术语
- 横切关注点 (Cross-cutting Concerns) :散落在系统各个角落、与核心业务逻辑无关,但又被多个模块需要的公共行为。
- 切面 (Aspect):对“横切关注点”的模块化封装。在 SpringBoot 中,它通常表现为一个带有
@Aspect注解的类。 - 连接点 (JoinPoint):程序执行过程中能够被拦截的所有位置。
- 切点 (Pointcut):用于筛选连接点的表达式。它决定了切面具体要在哪些连接点上生效。
- 通知 (Advice):切面在切点处执行的具体操作。
- 目标对象(Target):通知所对应的对象。
- 织入 (Weaving):将切面应用到目标对象,并生成代理对象的过程。
通知类型

- 前置通知 (Before):目标方法执行前触发。
- 后置通知 (After):目标方法执行后触发(无论成功或异常都会执行)。
- 返回通知 (AfterReturning):目标方法成功返回后触发。
- 异常通知 (AfterThrowing):目标方法抛出异常后触发。
- 环绕通知 (Around):它包裹了目标方法,可以在方法执行前后自定义逻辑,相当于前后通知;也可以用 try-catch 语句包裹方法执行语句,相当于异常通知;甚至可以决定是否执行目标方法(类似于拦截器)。
应用场景
- 日志记录:自定义日志记录注解,利用 AOP,一行代码即可实现日志记录。
- 耗时统计:利用 AOP 在目标方法的执行前后统计方法的执行时间,方便优化和分析。
- 事务管理:
@Transactional注解可以让 Spring 为我们进行事务管理比如回滚异常操作,免去了重复的事务管理逻辑。@Transactional注解就是基于 AOP 实现的。 - 权限控制:利用 AOP 在目标方法执行前判断用户是否具备所需要的权限,如果具备,就执行目标方法,否则就不执行。
- 接口限流:利用 AOP 在目标方法执行前通过具体的限流算法和实现对请求进行限流处理。
- 缓存管理:利用 AOP 在目标方法执行前后进行缓存的读取和更新。
常用语法
切面定义
使用 @Aspect 注解标注切面定义类,这个类的内部可以定义切点方法以及通知方法。
不同切面类中,默认按照切面类的类名字母排序:
- 对于目标方法前的通知方法,字母排名靠前的先执行。
- 对于目标方法后的通知方法,字母排名靠前的后执行。
可以用 @Order(数字) 加在切面类上控制通知执行顺序:
- 对于目标方法前的通知方法,数字小的先执行。
- 对于目标方法后的通知方法,数字小的后执行。
切点定义
把 @PointCut("切点表达式") 加到某个方法上,就相当于将方法名作为这个切点表达式的名称,之后其他需要这个切点表达式的地方可以简单替换为 切点表达式名称()。
通知方法定义
@Before("切点表达式"):前置通知。@After("切点表达式"):后置通知@AfterReturning("切点表达式"):返回通知。@AfterThrowing("切点表达式"):异常通知。@Around("切点表达式"):环绕通知。
TIP
@Around环绕通知需要自己调用原始方法,而其他通知无需调用原始方法。@Around环绕通知的返回值是 Object 类型。
切点表达式
- execution
- 语法结构:
execution(修饰符? 返回值 包名.类名.?方法名(参数) 异常?)- (
?表示前面的一小部分内容可以省略,并不用实际写出来。)
- 核心通配符:
*:匹配 一个 元素(任意返回值、任意类名、任意方法名、任意包的一层、一个参数)。..:匹配 多个 元素(任意层级的子包、任意个数的参数)。
- 逻辑运算符(组合多个切点表达式):
&&:同时满足。||:满足其一即可。!:排除。
- 语法结构:
- @annotation
@annotation(注解的全类名)指被注解标注的所有方法都属于同一个切点表达式,控制颗粒度更加精细。
连接点常用方法
@Around("webLog()")// 其他通知方法的参数类型是 JoinPointpublic Object around(ProceedingJoinPoint joinPoint) throws Throwable { // 获取目标类名 String className = joinPoint.getTarget().getClass().getName(); // 获取目标方法签名 Signature signature = joinPoint.getSignature(); // 获取目标方法名 String methodName = joinPoint.getSignature().getName(); // 获取目标方法运行参数 Object[] args = joinPoint.getArgs(); // 执行原始方法,获取返回值(环绕通知特有) Object res = joinPoint.proceed(); return res;}实现方式
- 运行时增强
- JDK 动态代理
- CGLIB 动态代理
- 编译时增强
- AspectJ
自动装配原理
概述
Spring Boot 自动装配的核心在于 @EnableAutoConfiguration 注解。 该注解通过 @Import 导入了 AutoConfigurationImportSelector 类。作为 ImportSelector 接口的实现者,它的核心职责是批量加载配置类。 具体流程是:它会读取 classpath 下 META-INF/spring.factories 文件中的全限定名,获取所有候选的自动配置类,再配合 @ConditionalXXX 条件注解进行过滤和筛选,最终将满足条件的配置类注入到 Spring 容器中。
源码分析
@SpringBootAppliaction 定义的源码:
// ...@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class}), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class})})public @interface SpringBootApplication { // ...}@EnableAutoConfiguration 定义的源码:
// ...@AutoConfigurationPackage@Import({AutoConfigurationImportSelector.class})public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};}AutoConfigurationImportSelector 的 selectImports 方法的源码:
public class AutoConfigurationImportSelector implements DeferredImportSelector, ... { public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
// ...}AutoConfigurationImportSelector 的 getAutoConfigurationEntry 源码:
AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { // 检查自动配置是否启用(enabled) // 如果注解 @EnableAutoConfiguration 被禁用(通过属性 spring.boot.enableautoconfiguration=false) // 就直接返回一个空的 AutoConfigurationEntry,不进行自动配置 if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { // 获取 @EnableAutoConfiguration 的注解属性 // 例如 exclude / excludeName 等,用于后续筛选候选自动配置类 AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 获取候选的自动配置类列表 // 主要从 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件读取 // 这些类都是可能需要导入的自动配置类 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 对候选自动配置类进行处理 // 去重,避免重复注册 configurations = this.removeDuplicates(configurations);
// 获取用户通过 exclude/excludeName 指定的排除类 Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// 校验排除类是否合法,抛异常提示错误配置 this.checkExcludedClasses(configurations, exclusions);
// 从候选类列表中移除排除类 configurations.removeAll(exclusions);
// 根据条件注解(如 @ConditionalOnClass / @ConditionalOnMissingBean)过滤候选类 configurations = this.filter(configurations, autoConfigurationMetadata);
// 发布 AutoConfigurationImportEvent 事件,允许监听器获取导入和排除的类信息 this.fireAutoConfigurationImportEvents(configurations, exclusions);
// 返回最终的 AutoConfigurationEntry,包括最终导入的配置类和排除的类 return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); }}参考
部分信息可能已经过时











