0%

springboot注解

Spring Boot 核心注解详解:从原理到实战应用

Spring Boot 的核心设计理念是 “约定大于配置”,而实现这一理念的核心载体就是注解。它通过注解替代了传统 Spring 中繁琐的 XML 配置,简化了 Bean 注册、自动配置、条件判断等核心流程。从 “注解作用→底层原理→使用场景→实战示例” 四个维度,系统讲解 Spring Boot 中最关键的注解,帮你理解注解背后的逻辑,灵活应对各类开发场景。

@SpringBootApplication:Spring Boot 应用的 “入口注解”

@SpringBootApplication 是 Spring Boot 项目的 “门面注解”,标注在主程序类上,表明该类是 Spring Boot 应用的入口,同时整合了三个核心注解的功能,是 “一站式开启 Spring Boot 功能” 的关键。

1. 注解本质:三个核心注解的组合

从源码可知,@SpringBootApplication复合注解,本质是 @SpringBootConfiguration@EnableAutoConfiguration@ComponentScan 的组合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 1. 声明 Spring Boot 配置类
@SpringBootConfiguration
// 2. 开启自动配置(核心)
@EnableAutoConfiguration
// 3. 开启组件扫描
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
// 核心属性:排除指定的自动配置类
Class<?>[] exclude() default {};
String[] excludeName() default {};
}

2. 子注解的核心作用

(1)@SpringBootConfiguration:Spring Boot 配置类标识
  • 本质:对 Spring 原生@Configuration注解的 “语义化封装”,源码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration // 底层就是 Spring 的 @Configuration
    public @interface SpringBootConfiguration {
    // 控制 Bean 是否代理(与 @Configuration 一致,默认 true,确保 Bean 单例)
    boolean proxyBeanMethods() default true;
    }
  • 作用:

    1. 标识当前类是 “Spring Boot 配置类”,类中通过 @Bean 注解声明的方法会被 Spring 扫描并注册为容器中的 Bean;
    2. @Configuration 功能完全一致,但更具语义性(明确是 Spring Boot 配置,而非普通 Spring 配置)。
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    @SpringBootConfiguration
    public class MyConfig {
    // 注册 User 类型的 Bean 到 Spring 容器
    @Bean
    public User user() {
    return new User("张三", 25);
    }
    }
(2)@EnableAutoConfiguration:自动配置的 “总开关”
  • 核心作用:开启 Spring Boot 的 “自动配置” 功能 —— 根据项目依赖(如引入 spring-boot-starter-web)自动加载对应的配置类(如 DispatcherServletAutoConfiguration),无需手动编写配置。

  • 底层原理:

    1. 导入 AutoConfigurationImportSelector 类,该类会读取 classpath:/META-INF/spring.factories 文件;
    2. 从文件中加载 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的所有自动配置类(如 DataSourceAutoConfigurationWebMvcAutoConfiguration);
    3. 通过 @ConditionalOnxxx 注解过滤出符合当前环境的配置类,注册到 Spring 容器。
  • 关键属性:exclude/excludeName—— 排除不需要的自动配置类(避免冲突),示例:

    1
    2
    3
    4
    5
    6
    7
    // 排除数据源自动配置(适合多数据源场景,手动配置数据源)
    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    public class DemoApplication {
    public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
    }
    }
(3)@ComponentScan:组件扫描的 “范围定义”
  • 作用:自动扫描并注册 Spring 组件(如 @Controller@Service@Repository@Component),默认扫描范围是 “主程序类所在的包及其子包”。

  • 排除规则:

    • 源码中通过excludeFilters排除了两类组件:
      1. TypeExcludeFilter:允许通过编程方式排除组件(扩展用);
      2. AutoConfigurationExcludeFilter:排除自动配置类(避免与 @EnableAutoConfiguration 重复扫描)。
  • 自定义扫描范围:若组件不在默认扫描范围内,可通过basePackages属性扩展:

    1
    2
    3
    4
    5
    // 扫描 com.example.demo(主包)和 com.example.other(外部包)的组件
    @SpringBootApplication(scanBasePackages = {"com.example.demo", "com.example.other"})
    public class DemoApplication {
    // ...
    }

3. 核心使用场景

  • 必须标注在 Spring Boot 主程序类上(含 main 方法的类),否则无法启动应用;
  • 需排除冲突的自动配置类时,通过 exclude 属性指定(如多数据源排除 DataSourceAutoConfiguration);
  • 组件不在默认扫描范围时,通过 scanBasePackages 扩展扫描路径。

@ConditionalOnxxx:自动配置的 “条件开关”

@ConditionalOnxxx 是 Spring Boot 自动配置的 “核心逻辑”,它是 Spring 原生 @Conditional 注解的变种,通过 “条件判断” 决定是否加载某个配置类或注册某个 Bean,确保自动配置 “按需生效”。

1. 核心注解分类与作用

根据判断条件的不同,@ConditionalOnxxx 可分为 Bean 相关类相关环境相关属性相关 等类别,常用注解如下:

注解类别 注解名称 核心作用 典型使用场景
Bean 相关 @ConditionalOnBean 容器中存在指定 Bean 时,才生效 配置 JdbcTemplate 前需存在 DataSource Bean
@ConditionalOnMissingBean 容器中不存在指定 Bean 时,才生效 自动配置默认 DataSource(用户未自定义时)
类相关 @ConditionalOnClass 类路径中存在指定类时,才生效 引入 spring-boot-starter-web 才加载 Web 配置
@ConditionalOnMissingClass 类路径中不存在指定类时,才生效 未引入 Redis 依赖时不加载 Redis 配置
环境相关 @ConditionalOnWebApplication 是 Web 应用(Servlet/Reactive)时,才生效 Web 应用才加载 DispatcherServlet 配置
@ConditionalOnNotWebApplication 非 Web 应用时,才生效 非 Web 应用加载定时任务配置
属性相关 @ConditionalOnProperty 配置文件中指定属性满足条件时,才生效 配置 spring.datasource.enabled=true 才加载数据源
@ConditionalOnExpression SpEL 表达式结果为 true 时,才生效 多条件组合判断(如 @ConditionalOnExpression("${spring.profiles.active} == 'prod'")
其他 @ConditionalOnJava 运行在指定 Java 版本范围内时,才生效 Java 11+ 才加载某配置(@ConditionalOnJava(JavaVersion.ELEVEN)
@ConditionalOnResource 类路径中存在指定资源文件时,才生效 存在 classpath:application-dev.yml 才加载开发配置

2. 实战示例:自动配置类中的条件判断

以 Spring Boot 内置的 DispatcherServletAutoConfiguration(Web 核心配置类)为例,看 @ConditionalOnxxx 的实际应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1. 类路径存在 DispatcherServlet 类(引入 web 依赖才满足)
// 2. 是 Servlet 类型的 Web 应用(排除 Reactive 应用)
@Configuration
@ConditionalOnClass(DispatcherServlet.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class DispatcherServletAutoConfiguration {

// 容器中不存在 DispatcherServlet 时,才自动注册(用户未自定义时)
@Bean
@ConditionalOnMissingBean(name = "dispatcherServlet")
public DispatcherServlet dispatcherServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(true);
return dispatcherServlet;
}
}

逻辑解读

  • 只有引入 spring-boot-starter-web(类路径存在 DispatcherServlet)且是 Servlet Web 应用时,才加载该配置类;
  • 只有用户未手动注册 dispatcherServlet Bean 时,才自动注册默认的 DispatcherServlet

3. 自定义条件判断(进阶)

若内置 @ConditionalOnxxx 无法满足需求,可自定义条件注解(基于 @Conditional):

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
26
27
// 1. 自定义条件注解:判断操作系统是否为 Windows
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(WindowsCondition.class) // 关联条件判断类
public @interface ConditionalOnWindows {
}

// 2. 实现条件判断逻辑
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取操作系统名称,判断是否为 Windows
String osName = context.getEnvironment().getProperty("os.name");
return osName != null && osName.contains("Windows");
}
}

// 3. 使用自定义条件注解
@Configuration
public class OsConfig {
// 仅 Windows 系统才注册该 Bean
@Bean
@ConditionalOnWindows
public WindowsService windowsService() {
return new WindowsService();
}
}

@ConfigurationProperties 与 @EnableConfigurationProperties:自定义配置绑定

@ConfigurationProperties 用于将 “配置文件中的属性” 与 “Java 类的字段” 进行批量绑定,替代传统的 @Value 注解(更适合复杂配置);@EnableConfigurationProperties 用于开启对 @ConfigurationProperties 注解的支持,二者配合使用实现自定义配置的优雅管理。

1. @ConfigurationProperties:配置绑定核心注解

(1)核心作用
  • 将配置文件中 “指定前缀” 的属性(如 custom.namecustom.age)自动映射到 Java 类的对应字段;
  • 支持类型转换(如配置文件中的字符串 18 自动转为 Integer 类型的 18);
  • 支持嵌套属性(如 custom.db.url 映射到 customDb.url 字段)。
(2)使用步骤
  1. 定义配置类并绑定前缀

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;

    // 1. 注册为 Spring Bean(@Component 或 @EnableConfigurationProperties 指定)
    @Component
    // 2. 绑定配置文件中前缀为 "custom" 的属性
    @ConfigurationProperties(prefix = "custom")
    public class CustomConfig {
    // 字段名与配置文件属性名一致(如 custom.name → name)
    private String name;
    private Integer age;
    // 嵌套属性(custom.db.url → db.url)
    private CustomDb db;

    // 必须提供 getter 和 setter(Spring 通过反射注入值)
    // ... 省略 getter/setter ...

    // 嵌套类
    public static class CustomDb {
    private String url;
    private String username;
    // ... 省略 getter/setter ...
    }
    }
  2. 配置文件中添加属性application.yml):

    1
    2
    3
    4
    5
    6
    7
    # 前缀为 "custom" 的配置
    custom:
    name: 张三
    age: 25
    db:
    url: jdbc:mysql://localhost:3306/test
    username: root
  3. 使用配置类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import javax.annotation.Resource;

    @RestController
    public class CustomController {
    // 注入自定义配置类
    @Resource
    private CustomConfig customConfig;

    @GetMapping("/custom")
    public CustomConfig getCustomConfig() {
    return customConfig;
    // 返回:{"name":"张三","age":25,"db":{"url":"jdbc:mysql://localhost:3306/test","username":"root"}}
    }
    }

2. @EnableConfigurationProperties:开启配置绑定支持

(1)作用场景
  • 若配置类未添加 @Component(不希望通过组件扫描注册),需通过 @EnableConfigurationProperties 手动开启绑定并注册为 Bean;
  • 明确指定需要绑定的配置类,避免扫描冗余。
(2)使用示例
1
2
3
4
5
6
7
8
9
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
// 开启 CustomConfig 的配置绑定,并将其注册为 Spring Bean
@EnableConfigurationProperties(CustomConfig.class)
public class Config {
// 无需再给 CustomConfig 添加 @Component
}

3. 配置提示:添加依赖解决无提示问题

“自定义配置时无提示”,原因是缺少配置元数据生成依赖。添加以下依赖后,IDE(如 IDEA)会自动生成配置提示:

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional> <!-- 仅编译时需要,不打包到生产环境 -->
</dependency>

生效方式:添加依赖后重新编译项目(mvn clean compile),IDE 会生成 META-INF/spring-configuration-metadata.json,从而支持配置项的补全和提示。

4. 与 @Value 的区别

对比维度 @ConfigurationProperties @Value
绑定方式 批量绑定(前缀匹配) 单个绑定(需指定完整属性名)
类型转换 自动支持(如 String → Integer/List) 需手动指定转换器(如 @Value("${custom.list:#{T(java.util.Arrays).asList('a','b')}}")
嵌套属性 原生支持(嵌套类) 不支持,需手动拼接属性名(如 ${custom.db.url}
配置提示 支持(需添加 configuration-processor) 不支持
适用场景 复杂配置(多属性、嵌套结构) 简单配置(单个属性)

@AutoConfigureBefore 与 @AutoConfigureAfter:自动配置类的 “顺序控制”

Spring Boot 自动配置类的加载顺序直接影响依赖关系(如 JdbcTemplateAutoConfiguration 依赖 DataSourceAutoConfiguration 先加载)。@AutoConfigureBefore@AutoConfigureAfter 用于控制自动配置类的加载顺序,确保依赖 Bean 先初始化。

1. 核心作用

注解名称 作用描述
@AutoConfigureBefore 当前配置类先于指定配置类加载
@AutoConfigureAfter 当前配置类后于指定配置类加载

2. 实战示例:控制配置类顺序

以 Spring Boot 内置的 JdbcTemplateAutoConfiguration 为例,它依赖 DataSourceAutoConfiguration 先加载(需先有 DataSource 才能创建 JdbcTemplate):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// JdbcTemplateAutoConfiguration 后于 DataSourceAutoConfiguration 加载
@Configuration
@ConditionalOnClass({DataSource.class, JdbcTemplate.class})
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class) // 关键:指定加载顺序
public class JdbcTemplateAutoConfiguration {

@Bean
@ConditionalOnMissingBean(JdbcOperations.class)
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
// 依赖 DataSource Bean,需确保 DataSource 已初始化
return new JdbcTemplate(dataSource);
}
}

3. 自定义配置类的顺序控制

若自定义自动配置类 MyConfig 需在 DataSourceAutoConfiguration 之后加载(依赖数据源),可添加 @AutoConfigureAfter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Configuration;

@Configuration
// 自定义配置类后于 DataSourceAutoConfiguration 加载
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyConfig {
// 依赖 DataSource 的 Bean 注册
@Bean
public MyService myService(DataSource dataSource) {
return new MyService(dataSource);
}
}

4. 注意事项

  • 仅对 “自动配置类”(通过 spring.factories 加载的类)生效,普通配置类(通过 @ComponentScan 扫描的类)不适用;
  • 若未指定顺序,自动配置类的加载顺序由 spring.factories 中定义的顺序决定,但不推荐依赖此默认顺序(显式指定更可靠)。

总结:注解的协同作用与最佳实践

Spring Boot 的核心注解并非孤立存在,而是通过 “协同工作” 实现 “约定大于配置” 的理念:

  1. @SpringBootApplication 是入口:整合配置类声明、自动配置开启、组件扫描,一站式启动应用;
  2. @ConditionalOnxxx 是条件:确保自动配置按需生效,避免冗余配置;
  3. @ConfigurationProperties 是绑定:将配置文件与 Java 类关联,简化自定义配置;
  4. @AutoConfigureBefore/After 是顺序:控制自动配置类加载顺序,解决依赖关系。

最佳实践建议

  1. 优先使用复合注解:如用 @SpringBootApplication 替代单独的 @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan,简化代码;
  2. 自定义配置用 @ConfigurationProperties:复杂配置优先用批量绑定,避免 @Value 重复编写;
  3. 显式控制配置顺序:自动配置类有依赖时,用 @AutoConfigureBefore/After 明确顺序,避免隐式依赖导致的问题;
  4. 条件判断精准化:自定义自动配置类时,用 @ConditionalOnClass/@ConditionalOnBean 缩小生效范围,提升性能

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10