春季:@Component与@Bean


459

我了解到@Component注释是在Spring 2.5中引入的,目的是通过使用类路径扫描摆脱xml bean的定义。

@Bean 是在3.0版本中引入的,可以与 @Configuration以完全摆脱xml文件并改用java config。

是否有可能重新使用@Component注释而不是引入@Bean注释?我的理解是,两种情况下的最终目标都是创建bean。


4
除了Configuration类,在任何地方都可以使用@Bean吗?
Willa 2014年


@Willa是的,有。叫做Lite mode。不建议这样做。参见此处:docs.spring.io/spring/docs/current/spring-framework-reference/…–
smwikipedia

8
我将其总结为一个方法,该方法@bean返回的是Spring bean的可自定义实例,同时@component定义了一个类,该类以后可在需要时由Spring IoC引擎实例化。
塞巴(Sebas)

Answers:


433

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

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

@Bean用于显式声明单个bean,而不是像上面那样让Spring自动执行。它使Bean的声明与类定义脱钩,并使您可以完全按照自己的选择创建和配置Bean。

要回答您的问题...

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

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


3
所以我只能@Component在需要自动接线时使用吗?似乎@Bean不能影响@Autowired
Jaskey 2015年

3
将'@component'用于基于服务的类,将'@Bean'作为工厂定制的对象,例如jdbc数据源
Junchen Liu

2
@Jaskey @Autowired@Bean如果您使用注释了您的bean类,可以使用@Configuration
@starcorn

6
抱歉,我无法理解您的解释。您清楚地理解了这一点,所以请您写清楚的说明或指向适当的文档?
亚历克斯·沃登

13
现在,我已经理解了这个概念(通过阅读其他人的答案),您的解释就很有意义了。这进一步告诉我,您的解释对尚不了解概念的任何人都是不好的。
亚历克斯·沃登

397

@Component 优选用于组件扫描和自动接线。

什么时候应该使用@Bean

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

所述@Bean注释返回一个对象该弹簧应在应用程序上下文豆注册。方法主体具有负责创建实例的逻辑。


5
我认为这是最合理的。如果我理解正确的话,@Component则自己进行类本身,而@Bean进行类方法(产生类对象的实例)。
jocull

182

让我们考虑根据某些动态状态来实现特定的实现。 @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


3
您如何称呼该示例类?
PowerFlower

1
@PowerFlower此方法应该在配置类中,并用@Configuration
Juh_ '19


97
  1. @Component 使用类路径扫描自动检测并配置Bean,而@Bean 显式声明单个Bean,而不是让Spring自动执行。
  2. @Component 不会从类定义中解耦 bean的声明,就像@Bean 解耦一样
  3. @Component是类级别的注释,而@Bean是方法级别的注释,该方法的名称用作Bean名称。
  4. @Component 不必与@Configuration注释一起使用,因为@Bean注释必须在用@Configuration注释的类中使用
  5. 我们不能创建一个bean使用@Component一类,如果类是外spring容器,而我们可以创建一个bean如果类是目前使用@Bean甚至一类外Spring容器
  6. @Component具有不同的专长,例如@ Controller,@ Repository和@Service,而@Bean 没有专长

3
4.实际上@Bean可以在非配置类中声明。这就是所谓的精简模式
-voipp

1
关于第5点,我认为我们在弹簧容器中放入了一个豆子。因此,每个类都在弹簧容器之外。我猜想应该奖励第5点
尤金

20

我看到了很多答案,几乎所有提到的@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的所有配置步骤。


5
我认为使用@Bean方法时不必从ApplicationContext获取User对象。您仍然可以@Autowire像情况下那样使用来获取bean @Component@Bean只是将Bean添加到Spring容器中,就像这样@Component做一样。区别如下。1.使用@Bean,您可以将第三方类添加到Spring Container。2.使用@Bean,您可以在运行时获得所需的接口实现(使用工厂设计模式)
Andy

20

您可以@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框架应用程序上下文中使用。现在,您可以使用依赖项注入和轻松在应用程序中共享/重用此bean @Autowired

因此,请注意@Bean注释是第三方类的包装器/适配器。您想使第三方类可用于您的Spring框架应用程序上下文。

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

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


1
如果以一个如何使用该豆的示例更新此答案,那就太好了
softarn

如果源代码不允许修改,您将如何在第三方类上包装@Bean?
veritas

16

使用@Component标记时,与使用香草豆声​​明方法(用注释@Bean)的POJO(普通的旧Java对象)相同。例如,下面的方法1和2将给出相同的结果。

方法1

@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声明保持在一起,这更加灵活等等。您甚至可能想要添加另一个非香草的SomeClass bean,如下所示:

@Bean
SomeClass strawberryClass(){
    return new SomeClass(new Integer(1));
}

10

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


6
  • @component及其特长(@ Controller,@ service,@ repository)允许使用类路径扫描进行自动检测。如果我们看到像@Controller,@service,@repository这样的组件类,Spring框架会使用组件扫描自动扫描@repository。
  • 另一方面,@Bean仅可用于在配置类中显式声明单个bean。
  • @Bean用于显式声明单个bean,而不是让spring自动执行。它从类定义中使bean分开声明。
  • 简而言之,@ Controller,@ service,@ repository用于自动检测,@ Bean用于创建与类分离的bean
    -@Controller
    公共类LoginController 
    {--code--}

    -@配置
    公共类AppConfig {
    @豆
    公共SessionFactory sessionFactory() 
    {--code--}



1

1.关于@Component
@Component功能类似于@Configuration。

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

由@Component注释的类,我们称之为Component of Spring。它是一个包含几个bean的概念。

Component class需要由Spring自动扫描以注册的那些bean 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();
      }
    }

0

以上答案的其他要点

假设我们有一个模块,该模块在多个应用程序中共享,并且包含一些服务。并非每个应用程序都需要所有内容。

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

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

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

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

每个应用程式中个别需要

因此,从本质上讲,可以使用@Bean将第三方类添加到上下文中。@Component,如果它仅在您的单个应用程序中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.