当前位置: 首页 > web >正文

@Configuration 与 @Component 的区别

  

目录

1、基本概念

1.1、@Component

1.2、@Configuration

2、代理类

2.1、保证Bean的单例性

2.2、提供完整的Bean生命周期

2.3、实现配置类的特殊行为

2.4、容器一致性保障

3、代理流程

3.1 代理流程分类

1、Full 模式(默认):

2、Lite 模式:

3.2、启动流程

3.3、底层机制

1、代理创建时机

2、代理类的工作方式

3.4、如何验证代理行为

4、性能考量

5、最佳实践建议


前言

        在Spring框架中,有许多常用的注解来定义类,以下常用的是@configuration和@component。

         Web 应用程序采用了经典的三层分层结构的话,在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释,而 @Component 就是对那些比较中立的类进行注释。

如下:

         <context:component-scan base-package=”com.*”>上面的这个是引入Component组件的例子,其中base-package表示为需要扫描的所有子包。

        从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

以下就是两者的区别:


1、基本概念

1.1、@Component

@Component 源码片段:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {String value() default "";
}
  •         Spring 核心注解,最基础的组件标记注解。

  • 作用:标识一个类作为 Spring 组件(Bean),会被组件扫描自动检测并注册到容器

  • 衍生注解

    • @Service(服务层)

    • @Repository(持久层)

    • @Controller(控制层)

  • 典型场景

    • 业务逻辑组件

    • 工具类组件

    • 非配置型的通用组件

1.2、@Configuration

@Configuration 源码片段

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {@AliasFor(annotation = Component.class)String value() default "";boolean proxyBeanMethods() default true;
}
  •         Spring 专门用于配置的增强型注解。

  • 本质:是一种特殊的 @Component(包含 @Component 元注解)

  • 核心能力

    • 定义 Bean 的装配规则

    • 支持跨 Bean 引用

    • 集成条件化配置(如 @Conditional

  • 典型场景

    • 应用主配置类

    • 数据库/缓存等基础设施配置

    • 第三方库集成配置

通过对比可以发现:

  • @Configuration 是 @Component 的派生注解(带有 @Component 元注解)。

  • @Configuration 特有的 proxyBeanMethods 属性控制代理行为。


2、代理类

Spring为@Configuration类生成CGLIB代理主要出于以下几个关键原因:

2.1、保证Bean的单例性

@Configuration类中的@Bean方法相互调用时:

@Configuration
public class AppConfig {@Beanpublic A a() {return new A(b()); // 调用b()方法}@Bean public B b() {return new B();}
}

无代理情况(如使用@Component):

  • 每次调用b()都会创建新的B实例

  • A和B无法保持单例性

有代理情况

  • 代理会拦截方法调用

  • 确保相同的b()总是返回同一个实例

  • 维护Spring容器的单例契约

2.2、提供完整的Bean生命周期

代理类能够:

  • 处理@PostConstruct/@PreDestroy等生命周期回调

  • 正确处理BeanFactoryAware等接口

  • 管理Bean的依赖关系

2.3、实现配置类的特殊行为

代理使得@Configuration 特有功能:

  • 支持 @Bean 方法间的调用

  • 完美配合 @Import/@ImportResource

  • 原生支持 @Profile 等条件化配置

  • 与 @Enable* 系列注解深度集成

2.4、容器一致性保障

如下图所示:

代码示例:

1、原始类:

@Configuration
public class DataConfig {@Beanpublic DataSource dataSource() {return new HikariDataSource(config());}@Beanpublic HikariConfig config() {return new HikariConfig();}
}

2、代理类伪代码:

public class DataConfig$$EnhancerBySpringCGLIB extends DataConfig {private BeanFactory beanFactory;@Overridepublic DataSource dataSource() {// 1. 检查Bean是否已存在if (beanFactory.containsBean("dataSource")) {return (DataSource) beanFactory.getBean("dataSource");}// 2. 通过父类方法创建新实例return super.dataSource(); // 会触发config()的代理逻辑}@Overridepublic HikariConfig config() {// 同样的单例保证逻辑if (beanFactory.containsBean("config")) {return (HikariConfig) beanFactory.getBean("config");}return super.config();}
}


3、代理流程

3.1 代理流程分类

1、Full 模式(默认):

需要完整代理。

2、Lite 模式

轻量级配置。

    使用 @Component + @Bean或 @Configuration(proxyBeanMethods = false)

    3.2、启动流程

    1. ConfigurationClassPostProcessor 开始处理

    2. 调用 ConfigurationClassUtils.checkConfigurationClassCandidate()

    3. 识别真正的 @Configuration 类(非lite模式)

    CGLIB代理生成过程

    // ConfigurationClassEnhancer 内部实现
    public Enhancer newEnhancer(Class<?> configSuperClass, ClassLoader classLoader) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(configSuperClass);enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});enhancer.setUseFactory(false);enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));enhancer.setCallbackFilter(CALLBACK_FILTER);enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());return enhancer;
    }
    1. 回调拦截器

    BeanMethodInterceptor:处理 @Bean 方法调用。

    BeanFactoryAwareMethodInterceptor:处理依赖注入。

    3.3、底层机制

    1、代理创建时机

    1. 在容器启动时,Spring检测到@Configuration

    2. 通过ConfigurationClassPostProcessor处理配置类

    3. 使用CGLIB生成子类代理

    2、代理类的工作方式

    生成的代理类会:

    1. 首次调用@Bean方法时,将返回的Bean注册到容器

    2. 后续调用相同方法时,直接从容器返回已注册的Bean

    3. 拦截所有@Bean方法调用,确保通过容器获取Bean

    3.4、如何验证代理行为

    示例代码

    @Configuration
    public class ConfigA {@Beanpublic B b() {return new B();}
    }@Component
    public class ConfigB {@Bean public C c() {return new C();}
    }

    测试验证

    @SpringBootTest
    public class ConfigTest {@Autowiredprivate ApplicationContext context;@Testpublic void testProxy() {// @Configuration类会被代理System.out.println(context.getBean(ConfigA.class).getClass()); // 输出: class com.example.ConfigA$$EnhancerBySpringCGLIB$$xxx// @Component类不会被代理System.out.println(context.getBean(ConfigB.class).getClass());// 输出: class com.example.ConfigB}
    }

    4、性能考量

    4.1 启动时间影响(测试数据)

    4.2 方法调用开销(纳秒级测量)

    • 代理创建开销:启动时会增加少量开销

    • 运行时性能:方法调用有轻微间接开销

    • 优化方案:对于不需要方法间调用的简单配置,可使用@Component+@Bean

    5、最佳实践建议

    1、使用@Configuration

    1. 需要定义多个相互依赖的Bean

    2. 需要完整的Spring配置功能

    3. 使用@Enable*系列注解

    2、使用@Component+@Bean

    1. 只有简单的Bean定义

    2. 不需要方法间调用

    3. 想避免代理开销

    3、禁用代理(特殊场景):

    @Configuration(proxyBeanMethods = false)
    public class MyConfig {// 此时行为类似于@Component
    }

    总结

            Spring为@Configuration生成代理是为了保证Bean的单例性和正确的依赖管理,这是Spring容器可靠性的重要基础设计。

    http://www.xdnf.cn/news/8536.html

    相关文章:

  • IPSec VPN参数配置显示详解
  • Jenkins构建信息收集脚本详解:打造全面的CI/CD监控体系
  • 阿里云API RAG全流程实战:从模型调用到多模态应用的完整技术链路
  • 《C 语言内存函数超详细讲解:从 memcpy 到 memcmp 的原理与实战》
  • 计量芯片在小家电产品破壁机中的电机保护应用案例
  • react+Mapbox GL实现标记地点、区域的功能
  • python开发环境管理和包管理
  • SpringBoot3集成Oauth2.1——5资源地址配置
  • MySQL--day6--单行函数
  • 【HCIA】端口隔离
  • threadPool.submit() 和 threadPool.execute()的区别
  • nvidia Thor U与qualcomm 8295 DMPIS算力测试对比
  • 日志分析-IIS日志分析
  • Oracle常用函数
  • 关于使用高德安卓api时so文件的坑
  • 解锁 BADBOX 2.0 的 DNS 密码箱
  • IP-guard发布新版本4.87.2241.0
  • matlab2007 和 microsoft access怎么连接?
  • java将rtsp转成flv在浏览器播放
  • 【HTML-9】深入理解HTML超链接标签:从基础到高级应用
  • 第R7周:糖尿病预测模型优化探索
  • YOLO12改进-Backbone-引入Swin Transformer替换backbone
  • 地理特征类可视化图像总结
  • Java面向对象编程核心:封装、继承与多态
  • AT24C02(I2C总线)
  • C# TCP协议全面指南:从可靠传输到企业级高并发的深度实践​
  • 当 BIM 遇见 GIS:GISBox 中 Revit 数据导入的技术联动与应用场景
  • 《AI 绘画崛起,人类艺术家如何在夹缝中寻找新机遇?》
  • 复杂工况下液压挖掘机工作臂系统创新设计与性能优化
  • 如何在STM32CubeMX下为STM32工程配置调试打印功能