611

我知道@Component在 spring 2.5 中引入了注释,以便通过使用类路径扫描来摆脱 xml bean 定义。

@Bean在 spring 3.0 中引入,可以用于@Configuration完全摆脱 xml 文件并使用 java config 代替。

是否可以重复使用@Component注释而不是引入@Bean注释?我的理解是最终目标是在这两种情况下创建 bean。

4

15 回答 15

540

@Component 首选 用于组件扫描和自动布线。

什么时候应该使用@Bean

有时自动配置不是一种选择。什么时候?假设您想从 3rd-party 库中连接组件(您没有源代码,因此无法使用 @Component 注释其类),因此无法进行自动配置。

@Bean注解返回一个对象,spring 应该在应用程序上下文中注册为 bean。方法的主体包含负责创建实例的逻辑。

于 2016-11-29T08:40:27.913 回答
529

@Component@Bean两件完全不同的事情,不要混淆。

@Component(and @Serviceand @Repository) 用于使用类路径扫描自动检测和自动配置 bean。带注释的类和 bean 之间存在隐式的一对一映射(即每个类一个 bean)。这种方法对布线的控制非常有限,因为它纯粹是声明性的。

@Bean用于显式声明单个 bean,而不是像上面那样让 Spring 自动完成。它将 bean 的声明与类定义分离,并允许您完全按照您的选择创建和配置 bean。

要回答你的问题...

是否可以重新使用@Component注释而不是引入@Bean注释?

当然,可能;但他们选择不这样做,因为两者完全不同。春天已经足够混乱,没有进一步搅浑水。

于 2012-05-15T15:59:09.537 回答
218

让我们考虑一下我想要根据某些动态状态的具体实现。 @Bean非常适合这种情况。

@Bean
@Scope("prototype")
public SomeService someService() {
    switch (state) {
    case 1:
        return new Impl1();
    case 2:
        return new Impl2();
    case 3:
        return new Impl3();
    default:
        return new Impl();
    }
}

但是,没有办法做到这一点@Component

于 2015-08-31T08:33:51.803 回答
200
  1. @Component使用类路径扫描自动检测和配置 bean,而 @Bean显式声明单个 bean,而不是让 Spring 自动执行。
  2. @Component不会将bean 的声明与类定义分离,而 @Bean将bean 的声明与类定义分离。
  3. @Component 是一个类级别的注解,而@Bean 是一个方法级别的注解,方法的名称作为 bean 的名称。
  4. @Component不需要与 @Configuration注释一起使用,因为 @Bean 注释必须在使用 @Configuration 注释的类中使用
  5. 如果类在 spring 容器之外,我们不能使用 @Component创建一个类的 bean,而我们可以使用 @Bean 创建一个类的 bean,即使该类存在于 spring 容器之外
  6. @Component 具有不同的特化,例如 @Controller、@Repository 和 @Service,而 @Bean没有特化。
于 2018-07-09T05:30:41.077 回答
111

这两种方法都旨在在 Spring 容器中注册目标类型。

区别在于@Bean适用于方法,而@Component适用于类型

因此,当您使用@Bean注释时,您可以控制方法主体中的实例创建逻辑(参见上面的示例)。使用@Component注释你不能。

于 2017-05-06T20:57:02.300 回答
49

我看到了很多答案,几乎所有提到的地方@Component都是用于扫描组件的自动装配,并且@Bean正是声明该 bean 以不同的方式使用让我展示一下它的不同之处。

  • @豆

首先,它是一个方法级别的注释。其次,您通常使用它在 Java 代码中配置 bean(如果您不使用 xml 配置),然后使用该 ApplicationContext.getBean方法从类中调用它。例子:

@Configuration
class MyConfiguration{
    @Bean
    public User getUser() {
        return new User();
    }
}

class User{
}    
        
// Getting Bean 
User user = applicationContext.getBean("getUser");
  • @零件

这是注释 bean 而非专用 bean 的一般方法。它是一个类级别的注释,用于通过 java 或 xml 配置避免所有配置内容。

我们得到这样的东西。

@Component
class User {
}

// to get Bean
@Autowired
User user;

而已。刚刚引入它是为了避免实例化和使用该 bean 的所有配置步骤。

于 2019-05-17T11:42:10.153 回答
30

您可以使用@Bean使现有的第三方类可用于您的 Spring 框架应用程序上下文。

@Bean
public ViewResolver viewResolver() {

    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

    viewResolver.setPrefix("/WEB-INF/view/");
    viewResolver.setSuffix(".jsp");

    return viewResolver;
}

通过使用@Bean注解,您可以将第三方类(它可能没有也@Component可能不使用 Spring)包装为 Spring bean。然后一旦使用 包装它@Bean,它就会作为一个单例对象并在您的 Spring 框架应用程序上下文中可用。您现在可以使用依赖注入和@Autowired.

所以认为@Bean注解是第三方类的包装器/适配器。您想让第三方类可用于您的 Spring 框架应用程序上下文。

通过@Bean在上面的代码中使用,我显式声明了一个 bean,因为在方法内部,我使用new关键字显式创建了对象。我也在手动调用给定类的 setter 方法。所以我可以改变前缀字段的值。所以这个手工工作被称为显式创建。如果我将@Component用于同一个类,则在 Spring 容器中注册的 bean 将具有前缀字段的默认值。

另一方面,当我们用 注释一个类时@Component,我们不需要手动使用new关键字。它由 Spring 自动处理。

于 2019-07-05T07:56:26.707 回答
22

当您使用@Component标签时,它与拥有一个带有香草 bean 声明方法(用 注释@Bean)的 POJO(普通旧 Java 对象)相同。例如,下面的方法 1 和 2 将给出相同的结果。

方法一

@Component
public class SomeClass {

    private int number;

    public SomeClass(Integer theNumber){
        this.number = theNumber.intValue();
    }

    public int getNumber(){
        return this.number;
    }
}

使用 'theNumber' 的 bean:

@Bean
Integer theNumber(){
    return new Integer(3456);
}

方法二

//Note: no @Component tag
public class SomeClass {

    private int number;

    public SomeClass(Integer theNumber){
        this.number = theNumber.intValue();
    }

    public int getNumber(){
        return this.number;
    }
}

两者都有豆子:

@Bean
Integer theNumber(){
    return new Integer(3456);
}

@Bean
SomeClass someClass(Integer theNumber){
    return new SomeClass(theNumber);
}

方法 2 允许您将 bean 声明放在一起,它更灵活等。您甚至可能想要添加另一个非 vanilla SomeClass bean,如下所示:

@Bean
SomeClass strawberryClass(){
    return new SomeClass(new Integer(1));
}
于 2018-01-19T18:23:29.567 回答
17

您有两种生成 bean 的方法。一种是创建一个带有注解的类@Component。另一种是创建一个方法并用@Bean. 对于那些包含方法 with 的类,@Bean应该用注解@Configuration 一旦你运行你的 spring 项目,带有@ComponentScan注解的类会扫描每个类@Component,并将这个类的实例恢复到 Ioc 容器。另一件事@ComponentScan是在其上运行方法@Bean并将返回对象作为 bean 恢复到 Ioc 容器。因此,当您需要根据当前状态决定要创建哪种 bean 时,您需要使用@Bean. 您可以编写逻辑并返回您想要的对象。另一件值得一提的是方法的名称,它@Bean是bean的默认名称。

于 2018-12-30T07:25:04.553 回答
15

Bean和组件的区别:

Bean和组件的区别

于 2020-04-30T05:52:30.990 回答
10
  • @component 及其特化(@Controller、@service、@repository)允许使用类路径扫描进行自动检测。如果我们看到像@Controller、@service、@repository 这样的组件类,Spring 框架会使用组件扫描自动扫描。
  • 另一方面,@Bean 只能用于在配置类中显式声明单个 bean。
  • @Bean 用于显式声明单个 bean,而不是让 spring 自动执行。它从类定义中对 bean 进行分隔声明。
  • 简而言之,@Controller、@service、@repository 用于自动检测,@Bean 用于从类中创建单独的 bean
    - @控制器
    公共类登录控制器
    {  - 代码 -  }

    - @配置
    公共类 AppConfig {
    @豆
    公共 SessionFactory sessionFactory()
    { - 代码 -  }
于 2018-03-12T18:51:26.177 回答
4

创建 @Bean 是为了避免在编译时耦合 Spring 和您的业务规则。这意味着您可以在 PlayFramework 或 JEE 等其他框架中重用您的业务规则。

此外,您可以完全控制如何创建 bean,而默认 Spring 实例化是不够的。

我写了一篇文章谈论它。

https://coderstower.com/2019/04/23/factory-methods-decoupling-ioc-container-abstraction/

于 2019-04-27T19:54:28.850 回答
3

以上答案的附加点

假设我们有一个在多个应用程序中共享的模块,它包含一些服务。每个应用程序都不需要全部。

如果在这些服务类上使用 @Component 并在应用程序中扫描组件,

我们最终可能会检测到比必要更多的 bean

在这种情况下,您要么必须调整组件扫描的过滤,要么提供即使未使用的 bean 也可以运行的配置。否则,应用程序上下文将不会启动。

在这种情况下,最好使用 @Bean 注释并仅实例化那些 bean,

每个应用程序都需要这些

因此,本质上,使用 @Bean 将第三方类添加到上下文中。和 @Component 如果它只是在你的单个应用程序中。

于 2020-04-29T09:17:14.413 回答
3

1. 关于@Component
@Component 的作用类似于@Configuration。

它们都表明带注释的类有一个或多个 bean 需要注册到Spring-IOC-Container.

@Component 注解的类,我们称之为Component of Spring。这是一个包含多个 bean 的概念。

Component class需要由 Spring 自动扫描以注册component class.

2.关于@Bean
@Bean 是用来注解的方法component-class(如上所述)。表示注解方法返回的实例需要注册到Spring-IOC-Container.

3. 结论
两者的区别比较明显,都用在different circumstances. 一般用法是:

    // @Configuration is implemented by @Component
    @Configuration
    public ComponentClass {

      @Bean
      public FirstBean FirstBeanMethod() {
        return new FirstBean();
      }

      @Bean
      public SecondBean SecondBeanMethod() {
        return new SecondBean();
      }
    }
于 2020-01-04T08:11:38.423 回答
2

Spring 支持@Component、@Service、@Repository 等多种类型注解。所有这些都可以在 org.springframework.stereotype 包下找到。

@Bean 可以在 org.springframework.context.annotation 包下找到。

当我们的应用程序中的类使用上述任何注释进行注释时,然后在项目启动期间 spring 扫描(使用 @ComponentScan)每个类并将类的实例注入 IOC 容器。@ComponentScan 会做的另一件事是运行带有 @Bean 的方法,并将返回对象作为 bean 恢复到 Ioc 容器。

@零件

如果我们用 @Component 或其他 Stereotype 注释标记一个类,这些类将使用类路径扫描自动检测。只要这些类在我们的基础包下,或者 Spring 知道要扫描另一个包,就会为这些类中的每一个创建一个新的 bean。

package com.beanvscomponent.controller;

import org.springframework.stereotype.Controller;

@Controller
public class HomeController {

    public String home(){
       return "Hello, World!";
   }

 }

带注释的类和 bean 之间存在隐式的一对一映射(即每个类一个 bean)。这种方法对布线的控制非常有限,因为它纯粹是声明性的。同样重要的是要注意构造型注释是类级别的注释。

@豆

@Bean 用于显式声明单个 bean,而不是像我们使用 @Controller 那样让 Spring 自动完成。它将 bean 的声明与类定义分离,并允许您完全按照您的选择创建和配置 bean。使用@Bean,您不会将此注释放在类级别。如果你试图这样做,你会得到一个无效的类型错误。@Bean 文档将其定义为:

Indicates that a method produces a bean to be managed by the Spring container.

通常,@Bean 方法在 @Configuration 类中声明。我们有一个用户类,我们需要实例化它,然后使用该实例创建一个 bean。这就是我之前所说的,我们对如何定义 bean 有更多的控制。

package com.beanvscomponent;

public class User {

private String first;
private String last;

public User(String first, String last) {
    this.first = first;
    this.last = last;
   }
}

正如我之前提到的,@Bean 方法应该在 @Configuration 类中声明。

package com.beanvscomponent;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ApplicationConfig {

@Bean
public User superUser() {
    return new User("Partho","Bappy");
   }

}

方法的名称实际上就是我们的 bean 的名称。如果我们在执行器中拉起 /beans 端点,我们可以看到定义的 bean。

{
"beans": "superUser",
"aliases": [],
"scope": "singleton",
"type": "com.beanvscomponent.User",
"resource": "class path resource 
    [com/beanvscomponent/ApplicationConfig.class]",
"dependencies": []
}

@Component 与 @Bean

在此处输入图像描述

我希望澄清一些关于何时使用@Component 和何时使用@Bean 的问题。这可能有点令人困惑,但是当您开始编写更多应用程序时,它会变得非常自然。

于 2021-11-07T07:38:54.090 回答