Spring中@Configuration和@Component有什么区别?

112

@ComponentScan 使用@Configuration@Component创建bean。这两个注释在交换时都可以正常工作。那么它们之间有什么区别呢?


1
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Component.html,http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html - JB Nizet
4
谢谢您,但请问您能否解释一下为什么这两个可以互换使用? - gaurav sood
11
除非您的配置类没有执行配置类通常要执行的任何操作,否则它们不会这样做。如上链接的文档所述,Configuration 在元注释中带有 Component,因此 Configuration 是一个 Component。反之则不成立。 - JB Nizet
感谢JB解决我的疑惑。 - gaurav sood
8个回答

107
@Configuration 表示一个类声明了一个或多个 @Bean 方法,并且可能被 Spring 容器处理以在运行时生成这些 bean 的定义和服务请求。 @Component 表示一个注释类是一个“组件”。当使用基于注释的配置和类路径扫描时,这些类被视为自动检测的候选对象。 @Configuration 元标记为 @Component,因此 @Configuration 类是组件扫描的候选对象。
您可以在此处查看更多信息:

http://docs.spring.io/spring-framework/docs/4.0.4.RELEASE/javadoc-api/org/springframework/context/annotation/Configuration.html

@Configuration也是一个@Component,但@Component不能像@Configuration那样起作用。


52
我很困惑这个回答。 - Dinesh
1
简明扼要的解释。谢谢。 - PowerAktar
1
答案没有解释任何东西。请注意,@Bean也可以在@Component类中声明(或者换句话说,链接的Javadoc的第一句话至多是误导性的)。 - Martin Andersson

55

它们之间有非常微妙的差别。让我提供一个非常快速的概述。

考虑以下情况:

@Configuration
public class MyConfig {

    @Bean
    public ServiceA aService(){
        return new ServiceA();
    }

    @Bean
    public ServiceB bService(){
        return new ServiceB(aService());
    }

}
请注意,ServiceB bean 依赖于 ServiceA,并且这不是自动装配。相反,它的编写方式意味着创建了一个新实例,而这实际上并非由 Spring 创建。而是由程序员使用 new 关键字创建的。

因此,如果我们使用 @Configuration,则它将使用 CGLIB 代理,并在这种情况下创建由 Spring 管理的单例 bean。如果您多次调用它,则返回 Spring 创建的相同 bean - 类似于自动装配的效果。

而使用 @Component,它不会进行代理处理,而是每次调用该方法时都会简单地返回一个新实例,而不是提供 Spring 管理的实例。(请记住,Spring Bean 是由 Spring 容器管理的内容,作为开发人员,您的工作是使用 @Autowired 等方法引入它们)。

通过 @Configuration(proxyEnabled=false) 可以实现与 @Component 相同的效果(这也称为轻量级模式处理)。因此,在轻量级模式下,您最终会执行以下操作:

@Configuration(proxyEnabled = false) // Lite mode, same effect as @Component
public class MyConfig {

    @Bean
    public ServiceA aService() {
        return new ServiceA();
    }
    
    @Autowired
    @Bean
    public ServiceB bService(ServiceA aServiceBean){
        return new ServiceB(aServiceBean);
    }

}

请参考这里以获得更详细的解释

希望对你有所帮助!祝你编码愉快!


5
这是正确的答案。谢谢!!! - masinger
应该使用proxyBeanMethods而不是proxyEnabled吗? - Sany Liew
应该使用proxyBeanMethods而不是proxyEnabled吗? - undefined

41

实际上,答案不完整。@Component表示一个被注解的类是一个“组件”。这样的类在使用基于注解的配置和类路径扫描进行自动检测时会被视为候选对象。

但是你可以创建一个名为MyConfiguration.java的类并将其用@Component标记,然后在其中添加@Beans声明。这样它看起来就像一个配置文件,主要区别在于当使用@Configuration注解类时,@Bean注解方法会使用CGLIB进行代理,代理代码在第一次调用方法返回bean之后,会再次调用该方法以返回上下文中的bean,而不是再次执行方法创建另一个实例(这是使用@Component和@Bean时发生的情况)。


根据代码 https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassUtils.java@Component 满足 isConfigurationCandidate,根据我的理解它也满足作为 Configuration 类。但是,行为上会有所不同吗? - R.G
1
@Juan Rada:你能给出一个实际的例子,说明何时使用@Component@Bean而不是@Configuration@Bean吗?前者是否与并行有关? - Treefish Zhang
@TreefishZhang Anand的回答提供了一个例子,说明这种区别很重要。但我认为这与并行性无关。 - Gerardo Cauich
这个有改变吗?我尝试了@Component@Configuration两种方式,但都没有执行@Bean方法超过一次。 - Wit

17

@Configuration - 它类似于 beans.xml,但是基于 Java 的 bean 配置。这意味着用此注解注释的类是配置 bean 的地方,并且将成为自动检测的候选对象。在此类中,使用 @Bean 注解标记方法,以返回该类的对象。

示例:

@Configuration
public class ConfigClass {

    @Bean
    public UserClass getObject() {
        return new UserClass();
    }
}

@Component - 如果一个类没有被标记为@Component,那么你就不能使用@Autowired来自动装配任何该类的实例。这意味着当你想要使用注解来自动装配任何类时,应该将该类注释为@Component。

示例:

@Component
public class A { .... }

public class B { 
    @Autowired
    A a;
    .....
    .....
}

Spring 参考文档: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html


2
我认为@Component的第二个声明需要澄清,因为它现在并不完全正确。@Autowire标记字段/参数以通过Spring bean实例由框架注入。然而,@Component仅标记类以通过组件扫描自动检测(顺便说一下,还有其他各种标记注释),这并不是必需的。Bean实例可以通过其他方式创建,例如通过@Configuration类、工厂、通过xml配置进行声明等。 - Pawel Zieminski

2

@Configuration 会默认导入 @Component。Controller、Service 和 Repository 是子组件(与 Configuration 一起),它们也是自动检测的候选对象。


2

@Configuration@Component都是Spring框架中使用的注释,但它们的作用不同。

@Configuration是一种类型级别的注释,表示一个类声明了一个或多个@Bean方法,并且可能被Spring容器处理,以在运行时生成bean定义和这些bean的服务请求。通常,带有@Configuration注释的类用作bean定义的来源。

@Component是一种类级别的注释,指示已注释的类为“组件”。当使用基于注释的配置和类路径扫描时,这些类将被视为自动检测的候选项。它是任何由Spring管理的组件或bean的通用原型。

简单地说,@Configuration用于定义bean及其依赖关系,而@Component用于通用目的的组件自动检测。

在大多数情况下,您会使用@Configuration来定义复杂配置的bean,使用@Component定义整个应用程序中经常使用的简单bean。

以下是一些官方参考资料,您可能会发现有帮助:

Spring框架文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-java

@Configuration JavaDoc:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html

@Component JavaDoc:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html


2
我在@reus的答案基础上进行了拓展。
  1. @Configuration 的作用是声明一个或多个@Bean方法,可以被Spring容器处理以在运行时生成bean定义和服务请求。
  2. 如果你查看@Configuration类,你会发现它是用@Component元注释进行元注释的。
@Target(value=TYPE)
 @Retention(value=RUNTIME)
 @Documented
 @Component
public @interface Configuration
  1. @Bean 允许我们以任何方式定义依赖项,这就是为什么 @Bean 注解在方法上方,我们手动创建一个 bean 对象并从该方法中返回它的原因。 @Component 允许我们快速定义依赖项,这就是为什么 @Component 放在类的上方。我们只在需要时注入它。

综上所述,这三点意味着- 要快速定义一个 bean,我们可以使用 @Component 注释进行类注释。要按照我们的喜好定义 bean(支持自定义要求),我们可以在 @Configuration 注释的类中使用 @Bean 编写 bean 定义。


-3

除了reos指出的差异之外。

@Configuration不能被@Component替换的原因如下:

区别在于如何处理bean之间的依赖关系。 请参考以下链接,了解详细的解释和示例: Configuration和Component之间的区别


1
欢迎提供解决方案的链接,但请确保您的答案即使没有链接也是有用的:在链接周围添加上下文,以便其他用户知道它是什么以及为什么存在,然后引用您链接的页面中最相关的部分,以防目标页面不可用。仅仅是一个链接的答案可能会被删除。 - M.A.R.
看了一下链接页面,它只提到了@Configuration的记忆化特性,就像上面@jcrada所提到的那样,但它并没有提到任何有关处理bean之间依赖关系的内容。 - Shadow Man

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接