Spring: @Component vs @Bean

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

@Bean是在spring 3.0中引入的,可以与@Configuration一起使用,以便完全摆脱xml文件,使用java配置代替。

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

416893 次浏览

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

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

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

回答你的问题…

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

当然,可能;但他们选择不这样做,因为这两者是完全不同的。春天已经够让人迷惑了,不要再把水弄脏了。

让我们考虑我想要依赖于某些动态状态的特定实现。 @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中没有办法做到这一点。

< >强@ component 适用于元件扫描和自动布线。< / p >

# EYZ0

有时自动配置不是一个选项。让我们想象一下,你想从第三方库连接组件(你没有源代码,所以你不能用@Component注释它的类),所以自动配置是不可能的。

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

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

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

因此,当您使用@Bean注释时,您就控制了方法主体中的实例创建逻辑(参见上面的例子)。而使用@Component注释则不行。

当您使用@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;
}
}

用豆子表示“数字”:

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

方法2

//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));
}
  • @component和它的特化(@Controller, @service, @repository)允许自动检测 使用类路径扫描。如果我们看到@Controller、@service、@repository这样的组件类,spring框架会使用component scan自动扫描
  • 另一方面,@Bean只能用于显式地声明配置类中的单个bean。
  • @Bean用于显式地声明单个bean,而不是让spring自动完成。它从类定义中分离bean声明。
  • 简而言之,@Controller、@service、@repository用于自动检测,@Bean用于从类中创建单独的bean
- @Controller
public class LoginController
{ --code-- }


- @Configuration
public class AppConfig {
@Bean
public SessionFactory sessionFactory()
{--code-- }
  1. @Component 汽车检测,并使用类路径扫描来配置bean,而@Bean 显式地声明是单个bean,而不是让Spring自动执行。
  2. @Component 不解耦是来自类定义的bean声明,@Bean 是来自类定义的bean声明。
  3. @Component是类级注释,而@Bean是方法级别注释,方法名作为bean名。
  4. @组件不需要和@Configuration一起使用注释,而@Bean注释必须是在类中使用@Configuration注解
  5. 如果类在spring容器之外,我们使用@Component来无法创建bean;如果类在在弹簧容器外面中,我们使用@Bean来可以创建一个bean
  6. @组件有不同的专门化,像@控制器,@存储库和@服务,而@Bean有没有专门化
您有两种生成bean的方法。 一种方法是创建一个标注为@Component的类。 另一种方法是创建一个方法并用@Bean注释它。对于那些包含@Bean方法的类,应该使用@Configuration进行注释 运行spring项目后,带有@ComponentScan注释的类将扫描每个带有@Component注释的类,并将该类的实例恢复到Ioc容器。@ComponentScan要做的另一件事是运行带有@Bean的方法,并将返回对象作为bean恢复到Ioc容器。 因此,当您需要根据当前状态决定要创建哪种类型的bean时,您需要使用@Bean。您可以编写逻辑并返回所需的对象。 另一件值得注意的事情是带有@Bean的方法的名称是bean的默认名称

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

此外,在默认的Spring实例化还不够的情况下,您可以完全控制如何创建bean。

我写了一篇关于它的文章。

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

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

  • @ bean
首先,它是一个方法级注释。 其次,通常使用它在Java代码中配置bean(如果不使用xml配置),然后使用类从类中调用它 # EYZ0方法。例子:< / p >
@Configuration
class MyConfiguration{
@Bean
public User getUser() {
return new User();
}
}


class User{
}
        

// Getting Bean
User user = applicationContext.getBean("getUser");
  • @ component
这是注释bean的一般方法,而不是专门的bean。 它是一个类级注释,用于避免通过java或xml配置的所有配置内容

我们得到这样的结果。

@Component
class User {
}


// to get Bean
@Autowired
User user;

就是这样。引入它只是为了避免实例化和使用该bean的所有配置步骤。

您可以使用@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。

因此,可以将@Bean注释看作第三方类的包装器/适配器。您希望使第三方类对Spring框架应用程序上下文可用。

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

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

< p > # EYZ0 < br > @Component的功能类似于@Configuration 它们都表明带注释的类有一个或多个bean需要注册到Spring-IOC-Container 由@Component注释的类,我们称之为Component of Spring。它是一个包含多个bean的概念。

Component class需要由Spring自动扫描来注册component class中的那些bean < p > # EYZ0 < br > @Bean用于注释component-class方法(如上所述)。它表示由带注释的方法返回的实例需要注册到Spring-IOC-Container.

< p > # EYZ0 < br > 它们之间的区别是比较明显的,它们在different circumstances中使用。 一般用法是:

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


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


@Bean
public SecondBean SecondBeanMethod() {
return new SecondBean();
}
}

以上答案的附加分数

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

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

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

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

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

每个应用程序都需要哪些

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

Bean和Component的区别:

 Bean和组件之间的差异

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

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

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

@ component

如果我们用@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用于显式地声明单个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": []
}

@组件vs @Bean

enter image description here

我希望这澄清了什么时候使用@Component和什么时候使用@Bean的一些问题。这可能有点令人困惑,但随着您开始编写更多的应用程序,它将变得非常自然。