【Spring】@Component VS @Configuration


在 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 底层处理流程

  1. Spring 启动时, ComponentScanAnnotationParser 解析 @ComponentScan 路径;
  2. 扫描所有标注 @Component(含衍生注解)的类,封装为 BeanDefinition
  3. 容器根据 BeanDefinition ,调用构造方法实例化对象;
  4. 完成依赖注入、初始化后,将 原生对象存入单例池。

关键:无任何代理增强,类中的方法调用,为原生 Java 方法调用。

2. @Configuration 底层处理流程

  1. 因标注 @Component,优先被扫描为配置类 BeanDefinition
  2. ConfigurationClassPostProcessor 后置处理器增强配置类:
  • 默认开启 proxyBeanMethods=true,使用 **CGLIB 动态代理 ,**创建配置类代理对象;
  • 拦截内部 @Bean 方法,保证多次调用返回同一个单例 Bean;
  1. 解析内部所有 @Bean 方法,注册为独立 Bean;
  2. 代理对象存入容器,保证 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;
    }
}

规范

  1. 配置类内部 @Bean 方法相互调用 :必须保留默认 proxyBeanMethods=true
  2. 纯配置类、无内部方法调用:可设置为 false,提升启动性能。

五、开发规范

  1. 分层注解规范
  • Web 层:@Controller
  • 业务层:@Service
  • 数据层:@Repository
  • 通用组件:@Component
  • 配置类:@Configuration
  1. 禁止混用场景
  • 禁止在业务类上使用 @Configuration;
  • 禁止在配置类中编写业务逻辑;
  • 禁止使用 @Component 替代 @Configuration 注册第三方 Bean。
  1. 性能优化规范
  • 无内部 @Bean 方法调用的配置类,添加 proxyBeanMethods = false
  • 组件扫描路径精准配置,避免扫描无关包,提升启动速度。
  1. Bean 依赖规范
  • 配置类中 @Bean 方法 优先使用参数注入,替代 @Autowired;
  • 业务组件中使用 @Autowired 注入 @Component 修饰的 Bean。

本文由mdnice多平台发布

相关推荐
AskHarries1 天前
为什么大多数人创业第一步就错了
人工智能·后端
tyung1 天前
Go 手写二叉堆优先队列:避开 container/heap 的性能陷阱
数据结构·后端·go
Nirvana在掘金1 天前
MySQL 事务隔离级别 锁 高并发场景优化经验
后端·mysql
李小狼lee1 天前
《spring如此简单》第二节--IOC思想的实现,容器是什么
后端·面试
GetcharZp1 天前
深入浅出 etcd:从 K8s 灵魂到 Golang 实战,分布式系统的“定海神针”!
后端
hikktn1 天前
企业级Spring Boot应用管理:从零打造生产级启动脚本
java·spring boot·后端
SimonKing1 天前
别再死磕 Elasticsearch 了,这个轻量级搜索引擎更香
java·后端·程序员
Gopher_HBo1 天前
阻塞队列之ArrayBlockingQueue
后端
怕浪猫1 天前
小厂三年我现在怎么样了
后端·面试