【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多平台发布

相关推荐
喵个咪3 小时前
go-wind-cms 微服务架构设计:为什么基于 Kratos?
后端·微服务·cms
神奇小汤圆3 小时前
百度面试官:Redis 内存满了怎么办?你有想过吗?
后端
喵个咪3 小时前
Headless 架构优势:内容与展示解耦,一套 API 打通全端生态
前端·后端·cms
开心就好20253 小时前
HTTPS超文本传输安全协议全面解析与工作原理
后端·ios
小江的记录本3 小时前
【JEECG Boot】 JEECG Boot——数据字典管理 系统性知识体系全解析
java·前端·spring boot·后端·spring·spring cloud·mybatis
神奇小汤圆3 小时前
Spring Batch实战
后端
喵个咪3 小时前
传统 CMS 太笨重?试试 Headless 架构的 GoWind,轻量又强大
前端·后端·cms
程序员木圭3 小时前
07-数组入门必看!Java数组的内存分析02
java·后端
喵个咪3 小时前
Go 语言 CMS 横评:风行 GoWind 对比传统 PHP/Java CMS 核心优势
前端·后端·cms