在 Spring 生态开发中,**@Component** 和 @Configuration 是管理 Bean 实例、实现依赖注入的核心注解,也是 Java 后端开发必须吃透的基础知识点。
二者看似都是向 Spring 容器注册组件,底层逻辑、使用场景、生效机制却天差地别。
====== 🌟 青柠来相伴,代码更简单。🌟 ======
📚 本文所有内容,我都整理成了文档资料。👇
🎯 搜索【青柠代码录】,关键字:青柠合集
🚀 即可查看所有博客文章 ~
====== 🌟 ================= 🌟 ======
一、基础认知
@Component :我是一个普通组件,让 Spring 管理我就行,适用于所有业务类、工具类。
@Configuration :我是一个配置管家,负责给 Spring 批量注册 Bean,适用于全局配置、第三方集成。
二者是 Spring 容器管理的基础,正确使用是实现解耦、规范开发的核心前提。
1. @Component 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
String value() default "";
}
- 核心作用 : 通用型组件注解,将普通 Java 类,标记为 Spring 容器管理的 Bean,是 Spring 中最基础的组件注册注解。
- 衍生注解:@Controller(Web 层)、@Service(业务层)、@Repository(数据层),均是 @Component 的语义化扩展,底层逻辑完全一致。
- 注册方式 :Spring 通过 组件扫描(@ComponentScan) ,自动扫描标注该注解的类,实例化后存入单例池。
2. @Configuration 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
String value() default "";
boolean proxyBeanMethods() default true;
}
- 核心作用 : 配置类专用注解 ,标记一个类为 Spring 配置类,替代传统 XML 配置文件,用于 集中定义、组装 Bean。
- 底层特性 :本身被 @Component 修饰,本质也是一个组件,但具备 代理增强能力。
- 核心能力:支持在类内部,通过 @Bean 注解,手动创建 Bean,实现复杂 Bean 的初始化、依赖注入。
二、核心区别
| 对比维度 | @Component | @Configuration |
|---|---|---|
| 注解本质 | 普通组件注解 | 配置类注解(继承 @Component) |
| 核心用途 | 注册业务 / 工具类 Bean | 定义配置类、手动创建 / 组装 Bean |
| Bean 定义方式 | 直接标注在类上,自动实例化 | 标注在类上,内部通过 @Bean 方法定义 Bean |
| 代理机制 | 无代理,原生对象 | 默认开启 CGLIB 代理(proxyBeanMethods=true) |
| 方法调用特性 | 普通方法调用,每次创建新对象 | 代理调用,保证 Bean 单例(容器内唯一) |
| 依赖注入方式 | 自动注入(@Autowired) | 支持方法参数注入、成员变量注入 |
| 使用场景 | 业务层、工具类、通用组件 | 配置类、第三方 Bean 注册、全局配置 |
| 生命周期管理 | 标准 Spring Bean 生命周期 | 配置类优先初始化,优先于普通组件 |
| 多实例支持 | 可配合 @Scope 定义多例 | 内部 @Bean 默认单例,可自定义作用域 |
| 优先级 | 业务开发主流使用 | 框架配置、第三方集成、全局配置专用 |
三、底层原理
1. @Component 底层处理流程
- Spring 启动时,
ComponentScanAnnotationParser解析 @ComponentScan 路径; - 扫描所有标注 @Component(含衍生注解)的类,封装为
BeanDefinition; - 容器根据
BeanDefinition,调用构造方法实例化对象; - 完成依赖注入、初始化后,将 原生对象存入单例池。
关键:无任何代理增强,类中的方法调用,为原生 Java 方法调用。
2. @Configuration 底层处理流程
- 因标注 @Component,优先被扫描为配置类
BeanDefinition; ConfigurationClassPostProcessor后置处理器增强配置类:
- 默认开启
proxyBeanMethods=true,使用 **CGLIB 动态代理 ,**创建配置类代理对象; - 拦截内部 @Bean 方法,保证多次调用返回同一个单例 Bean;
- 解析内部所有 @Bean 方法,注册为独立 Bean;
- 代理对象存入容器,保证 Bean 方法调用的单例性。
核心特性 :配置类代理模式,解决 @Bean 方法相互调用时的多例问题。
四、案例实战
场景 1:@Component 注册通用业务组件
适用场景:自定义工具类、业务辅助类、无分层的通用组件。
import org.springframework.stereotype.Component;
/**
* 字符串工具类:注册为 Spring Bean
* 开发中,通用工具类优先使用 @Component
*/
@Component
public class StringUtils {
/**
* 判空方法
*/
public boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
}
注入使用:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
// 自动注入 @Component 修饰的 Bean
@Autowired
private StringUtils stringUtils;
public void checkUsername(String username) {
if (stringUtils.isEmpty(username)) {
throw new RuntimeException("用户名不能为空");
}
}
}
场景 2:@Configuration 定义配置类 + 注册第三方 Bean
适用场景:集成第三方框架(Redis、MQ、MyBatis)、自定义线程池、全局配置类。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 线程池配置类
* 开发中,所有第三方 Bean、全局配置均使用 @Configuration
*/
@Configuration
public class ThreadPoolConfig {
/**
* 定义全局单例线程池 Bean
* @Bean 注解:方法返回值注册为 Spring Bean
* 方法名默认作为 Bean 名称,可通过 @Bean("customExecutor") 自定义
*/
@Bean
public ExecutorService taskExecutor() {
return Executors.newFixedThreadPool(10);
}
/**
* 依赖注入:直接将上方 Bean 作为参数注入
* 配置类内部依赖自动关联,无需手动 @Autowired
*/
@Bean
public TaskService taskService(ExecutorService taskExecutor) {
TaskService taskService = new TaskService();
taskService.setExecutor(taskExecutor);
return taskService;
}
}
场景 3:核心坑点:proxyBeanMethods 代理机制
错误示例(无代理,产生多例 Bean)
// 关闭代理:proxyBeanMethods = false
@Configuration(proxyBeanMethods = false)
public class TestConfig {
@Bean
public User user() {
return new User();
}
@Bean
public Order order() {
Order order = new Order();
// 此处调用 user() 方法,会创建新的 User 对象,破坏单例!
order.setUser(user());
return order;
}
}
问题 :关闭代理后,方法调用为原生调用,每次 user() 都会 new 新对象,导致容器内存在多个 User 实例。
正确示例(默认开启代理,保证单例)
// 默认:proxyBeanMethods = true,开启 CGLIB 代理
@Configuration
public class TestConfig {
@Bean
public User user() {
return new User();
}
@Bean
public Order order() {
Order order = new Order();
// 代理拦截:调用的是容器中的单例 User,不会创建新对象
order.setUser(user());
return order;
}
}
规范:
- 配置类内部 @Bean 方法相互调用 :必须保留默认
proxyBeanMethods=true; - 纯配置类、无内部方法调用:可设置为
false,提升启动性能。
五、开发规范
- 分层注解规范
- Web 层:@Controller
- 业务层:@Service
- 数据层:@Repository
- 通用组件:@Component
- 配置类:@Configuration
- 禁止混用场景
- 禁止在业务类上使用 @Configuration;
- 禁止在配置类中编写业务逻辑;
- 禁止使用 @Component 替代 @Configuration 注册第三方 Bean。
- 性能优化规范
- 无内部 @Bean 方法调用的配置类,添加
proxyBeanMethods = false; - 组件扫描路径精准配置,避免扫描无关包,提升启动速度。
- Bean 依赖规范
- 配置类中 @Bean 方法 优先使用参数注入,替代 @Autowired;
- 业务组件中使用 @Autowired 注入 @Component 修饰的 Bean。
本文由mdnice多平台发布