@Configuration 详解:Spring 配置类的核心注解

@Configuration 详解:Spring 配置类的核心注解

@Configuration 是 Spring Framework 提供的注解,用于标记一个类为配置类 。它告诉 Spring 容器:这个类中包含了一个或多个 @Bean 定义方法,这些方法返回的对象需要被注册为 Spring 容器中的 Bean。

一、基本用法

java 复制代码
@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

在 Spring Boot 启动类中,@SpringBootApplication 已经包含了 @Configuration,所以启动类本身就是一个配置类。你可以在启动类中直接添加 @Bean 方法。

java 复制代码
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

二、@Configuration 的本质

@Configuration 类在 Spring 容器中被 ConfigurationClassPostProcessor(一个 BeanFactoryPostProcessor)处理。这个处理器会解析 @Configuration 类,提取所有 @Bean 方法,并将它们转换为 Spring 容器中的 Bean 定义。与其他 @Component 类的处理方式不同,@Configuration 类中的 @Bean 方法会被 CGLIB 代理,保证方法之间互相调用时返回的是同一个 Bean 实例。

@Configuration vs @Component

@Component 标注的类也可以通过 @Bean 方法定义 Bean,但 @Configuration@Component 在处理 @Bean 方法时有本质区别:

对比维度 @Configuration @Component
代理方式 CGLIB 代理 不代理
方法间调用 返回容器中的单例 Bean 每次调用都执行方法体,创建新实例
Bean 定义模式 Full 模式 Lite 模式
适用场景 需要方法间调用保证单例 不需要方法间调用

示例说明:

java 复制代码
@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        // userService 内部调用 userDao() 方法
        // 由于 CGLIB 代理,userDao() 返回的是容器中已有的单例 Bean
        return new UserService(userDao());
    }
    
    @Bean
    public UserDao userDao() {
        return new UserDao();
    }
}

如果这个类用 @Component 而不是 @ConfigurationuserService() 中调用 userDao() 时不会经过 Spring 容器,会直接执行方法体,每次都创建一个新的 UserDao 实例,破坏单例性。

三、@Bean 方法详解

@Bean 方法的作用是将方法返回值注册为 Spring 容器中的 Bean。

java 复制代码
@Configuration
public class AppConfig {
    // Bean 名称默认为方法名 dataSource
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
    }
    
    // 自定义 Bean 名称
    @Bean("myDataSource")
    public DataSource dataSource2() {
        return new HikariDataSource();
    }
}

方法参数注入

@Bean 方法有参数时,Spring 会自动从容器中查找匹配的 Bean 并注入:

java 复制代码
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}

Spring 会从容器中查找 DataSource 类型的 Bean 作为参数传入。

指定 Bean 的作用域

java 复制代码
@Bean
@Scope("prototype")
public MyBean myBean() {
    return new MyBean();
}

初始化与销毁回调

java 复制代码
@Bean(initMethod = "init", destroyMethod = "cleanup")
public MyBean myBean() {
    return new MyBean();
}

四、与其他注解的配合

@ComponentScan

@Configuration 类通常与 @ComponentScan 配合使用,指定 Bean 的扫描路径。@SpringBootApplication 已经包含了 @ComponentScan,所以不需要单独添加。

java 复制代码
@Configuration
@ComponentScan("com.example.service")
public class AppConfig {
}

@PropertySource

@Configuration 类上使用 @PropertySource 加载自定义配置文件:

java 复制代码
@Configuration
@PropertySource("classpath:custom.properties")
public class AppConfig {
    @Value("${custom.value}")
    private String customValue;
}

@Import

@Configuration 类上使用 @Import 导入其他配置类:

java 复制代码
@Configuration
@Import({DatabaseConfig.class, SecurityConfig.class})
public class AppConfig {
}

@Profile

@Configuration 类或 @Bean 方法上使用 @Profile,控制配置在特定 Profile 下生效:

java 复制代码
@Configuration
@Profile("dev")
public class DevConfig {
    @Bean
    public DataSource dataSource() {
        // 开发环境数据源
    }
}

@Configuration
@Profile("prod")
public class ProdConfig {
    @Bean
    public DataSource dataSource() {
        // 生产环境数据源
    }
}

五、@Configuration 在 Spring Boot 中的位置

在 Spring Boot 项目中,@Configuration 类通常放在以下位置:

启动类

java 复制代码
@SpringBootApplication
public class Application {
    // 启动类本身就是配置类
}

独立的配置类

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    // 覆盖 Spring MVC 默认配置
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor());
    }
}
java 复制代码
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        return template;
    }
}

自动配置类

Spring Boot 的自动配置类本质上也是 @Configuration 类,但会加上条件注解控制生效时机:

java 复制代码
@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
public class DataSourceAutoConfiguration {
    @Bean
    @ConditionalOnProperty(name = "spring.datasource.type")
    public DataSource dataSource() {
        // ...
    }
}

六、@Configuration 与 Spring Boot 自动配置

Spring Boot 通过 @EnableAutoConfiguration 加载自动配置类。这些自动配置类就是 @Configuration 类,加上条件注解后决定何时生效。

自动配置的加载机制:

  1. @EnableAutoConfiguration 通过 AutoConfigurationImportSelectorMETA-INF/spring.factories(Spring Boot 2.7 之前)或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(Spring Boot 2.7 之后)读取自动配置类列表。
  2. 每个自动配置类都是 @Configuration 类,带有 @ConditionalOnXxx 条件注解。
  3. 条件满足时,配置类中的 @Bean 方法被执行,对应的 Bean 注册到容器中。

条件注解:

注解 条件
@ConditionalOnClass classpath 中存在指定类
@ConditionalOnMissingClass classpath 中不存在指定类
@ConditionalOnBean 容器中存在指定 Bean
@ConditionalOnMissingBean 容器中不存在指定 Bean
@ConditionalOnProperty 配置属性满足条件
@ConditionalOnWebApplication 是 Web 应用

七、常见问题

问题:@Bean 方法在 @Configuration 和 @Component 中的区别

这是最容易混淆的地方。在 @Component 类中定义 @Bean 方法,方法间相互调用时不经过 Spring 容器,不会保持单例。@Configuration 类中的 @Bean 方法会被 CGLIB 代理,保证单例性。

问题:@Configuration 类是否需要 @ComponentScan?

@Configuration 本身不带 @ComponentScan,但如果类上同时有 @SpringBootApplication,其中包含 @ComponentScan,默认会扫描启动类所在包及其子包。

问题:@Configuration 类是否需要放在指定位置?

@Configuration 类需要被 @ComponentScan 扫描到,或被 @Import 导入,或通过 @EnableConfigurationProperties 注册。@SpringBootApplication 的默认扫描范围是启动类所在包及所有子包。

八、最佳实践

  • @Configuration 类集中在专门的包中(如 config),便于管理
  • 不同的功能模块分开配置,比如 DataSourceConfigRedisConfigWebConfig 分别负责不同功能
  • 通过 @Profile 区分不同环境的配置,避免在代码中使用环境判断
  • 利用 @ConditionalOnMissingBean 提供默认实现,允许用户通过自定义 Bean 覆盖默认配置
  • 配置类中使用 @Bean 方法注入依赖时,通过方法参数注入,而不是在方法内部调用其他 @Bean 方法

九、总结

@Configuration 是 Spring 配置体系的基石。它定义了配置类,通过 @Bean 方法向容器注册 Bean。与 @Component 的区别在于,@Configuration 类中的 @Bean 方法会被 CGLIB 代理,确保方法间调用时返回容器中的单例 Bean。在 Spring Boot 中,@SpringBootApplication 本身就包含了 @Configuration,所以启动类本身就是一个配置类。自动配置的核心也是基于 @Configuration 配合条件注解实现的。

理解 @Configuration 的本质,就理解了 Spring 容器是如何从配置类中提取 Bean 定义的。在 Spring Boot 中,@Configuration 是管理 Bean 定义、覆盖默认配置、定制应用行为的主要入口。

相关推荐
sunshine22 girl1 小时前
Java学习一 环境配置2 安装和基本使用Idea
java·学习·intellij-idea
嘿嘿-663 小时前
Windows 一键使用 GPT-6 Astra:Codex CLI 配置教程
java·人工智能·windows·gpt·chatgpt·web
桦说编程3 小时前
【AtomicAgent系列1】变异测试——过去做不起,现在 agent 做得起
后端·ai编程·vibecoding
考虑考虑4 小时前
nginx打印请求日志
运维·后端·nginx
策案案案4 小时前
YOLO: 将AI Agents嵌入到IntelliJ IDEA
java·大数据·人工智能·笔记·yolo·microsoft·intellij-idea
IT_陈寒4 小时前
Python的切片赋值把我坑惨了,这不是bug是特性
前端·人工智能·后端
CoderLiu4 小时前
程序化工具调用(PTC)与动态工作流引擎:深入大模型工具调用的架构演进与实践
前端·人工智能·后端
fireworks995 小时前
SpringBoot2接入Knife4j
后端
wei_shuo5 小时前
数据迁移工具实战:KDMS自动化评估与量化决策体系解析
后端