ChatGPT解决这个技术问题 Extra ChatGPT

Spring:@Component 与 @Bean

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

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

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

除了 Configuration 类之外,还有其他地方可以使用 @Bean 吗?
@Willa 是的,有。这称为 Lite mode。而且不推荐。见这里:docs.spring.io/spring/docs/current/spring-framework-reference/…
我总结一下,带有 @bean 的方法返回一个可自定义的 spring bean 实例,而 @component 定义了一个类,稍后可能在需要时由 spring IoC 引擎实例化。
@Willa 是的,@Bean 可以在用 @Component 注释的类中使用。 “您可以在 @Configuration-annotated 或 @Component-annotated 类中使用 @Bean 注解。” docs.spring.io/spring-framework/docs/current/reference/html/…

S
Sebas

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

什么时候应该使用@Bean?

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

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


我认为这是最有意义的。如果我理解正确,@Component 继续类本身,而 @Bean 继续类方法(产生类对象的实例)。
在我阅读 what if you don't have the source codes 之前,我一直处于困境中?然后,卡布拉姆!当然,@Component 如果您拥有源代码,但如果您想将其他没有源代码的类组件化,那么 @Bean。我敢肯定还有其他的不同,但是女士们先生们,这很明确。
简单直接,谢谢大佬。
我还是没明白 - 如果您没有源代码,spring 如何知道我们@Bean编辑的类?
@ajaysinghnegi:您不拥有应用程序所依赖的库中的代码,但您(和 Spring)知道这些库中的类。
s
skaffman

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

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

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

要回答你的问题...

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

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


所以我只能在需要自动装配时使用 @Component 吗?似乎 @Bean 不能影响 @Autowired
使用“@component”作为基于服务的类,使用“@Bean”作为工厂更量身定制的对象,例如 jdbc 数据源
@Jaskey 如果您使用 @Configuration 注释了您的 bean 类,您可以将 @Autowired@Bean 一起使用
抱歉,我一个字都听不懂你的解释。您清楚地理解这一点,所以请您写一个清晰的解释或指向适当的文档?
现在我理解了这个概念(通过阅读其他人的答案),你的解释是有道理的。这更加告诉我,您的解释对任何不了解这些概念的人都没有好处。
o
outdev

让我们考虑一下我想要根据某些动态状态的具体实现。 @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 无法做到这一点。


你怎么称呼那个示例类?
@PowerFlower 这个方法应该在一个配置类中,用 @Configuration 注释
@Lookup public SomeService getSomeService(){ return null;因为它是原型范围的
U
Unmitigated

@Component 使用类路径扫描自动检测和配置 bean,而 @Bean 显式声明单个 bean,而不是让 Spring 自动执行。 @Component 不会将 bean 的声明与类定义分离,而 @Bean 将 bean 的声明与类定义分离。 @Component 是一个类级别的注解,而 @Bean 是一个方法级别的注解,方法的名称作为 bean 的名称。 @Component 不需要与@Configuration 注释一起使用,而@Bean 注释必须在使用@Configuration 注释的类中使用。如果类在 Spring 容器之外,我们不能使用 @Component 创建类的 bean,而我们可以使用 @Bean 创建类的 bean,即使该类存在于 Spring 容器之外。 @Component 具有不同的特化,例如 @Controller、@Repository 和 @Service,而 @Bean 没有特化。


4. 实际上@Bean 可以在非配置类中声明。它被称为精简模式
关于第 5 点。我想我们在 spring 容器中放了一个 bean。因此,每个类都在 spring 容器之外。我想,第 5 点应该得到奖励
这是弹簧靴回答最多的问题之一。
Point 5.“Spring容器外”的定义是什么?
@FuadEfendi 如果该类在库中,则无法注释源代码。但是你可以实例化它并用它制作一个 Bean。
C
Community

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

不同之处在于 @Bean 适用于方法,而 @Component 适用于 types

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


什么是类型?
@JacFrall:简单地说,类型就是一个类。该类的任何实例都属于该类的类型。因此,如果您有一个“Dog”类并创建一个 Dog rex = new Dog(),则名为“rex”的对象属于“Dog”类型,因为它是“Dog”类的一个实例。
不仅如此。春天处理的那些豆子不同。刚出事了。 @ConditionalOnBean(SomeBean) 不起作用,如果 SomeBean 由 @Bean 注解组成。但如果 SomeBean 是 @Component,它就可以工作。尽管调用了 @Bean=> SomeBean 方法并且创建了 bean 并将其添加到上下文中,但这甚至不起作用。尽管如此,@ConditionaOnBean 还是无法看到这个 bean(或者可能是使用 @Bean vs (@Component @Service @Respository @Service @Configuration) 创建的 bean 的顺序不同,并且在扫描完成后在应用程序上下文的末尾调用了 @Bean 注释方法)。
P
Paulo Merson

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


我认为当您使用 @Bean 方法时,没有必要从 ApplicationContext 获取 User 对象。您仍然可以像使用 @Component 一样使用 @Autowire 来获取 bean。 @Bean 只是将 Bean 添加到 Spring Container 中,就像 @Component 所做的那样。区别如下。 1. 使用@Bean,您可以将第三方类添加到 Spring Container。 2.使用@Bean,您可以在运行时获得所需的接口实现(使用工厂设计模式)
@Andy您仍然可以使用@Autowire 来获取bean,就像在@Component 的情况下一样?当您使用@Autowired 和User 用户时,它将采用默认的实现权限。如何对其进行编码以采取具体实现。
有几种方法可以实现这一目标。假设你有 Employee 接口 & 2 实现 EmployeeImpla & EmployeeImplb。假设您有一个名为 SalaryImpl 的类,它被注释为 @Component 并且您想在该类中使用 EmployeeImplA 实现。选项 1 您可以执行类似 Employee employeeImplA 选项 2 @Qulaifier("employeeImplA") Employee employee 的操作
e
elvis

您可以使用 @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 自动处理。


如果这个答案也更新了一个关于如何使用该 bean 的示例,那就太好了
如果源代码不允许修改,您将如何将 @Bean 包装在第三方类上?
用法 ``` @AutoWired ViewResolver viewResolver ```
S
SomeGuy

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

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

D
Dai Niu

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


A
AzarEJ

Bean和组件的区别:

https://i.stack.imgur.com/e8RlG.png


对于第 3 方库,我认为 @Bean 是可能的,因为 @Bean 不需要在 Spring 容器中存在类定义,相反 @Component 在这种情况下是不可能的。
a
alok

@component 及其特化(@Controller、@service、@repository)允许使用类路径扫描进行自动检测。如果我们看到像@Controller、@service、@repository 这样的组件类,Spring 框架会使用组件扫描自动扫描。

另一方面,@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-- }

D
Daniel Andres Pelaez Lopez

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

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

我写了一篇文章谈论它。

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


P
Partho

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

https://i.stack.imgur.com/zJpux.png

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


请在上面做一个小项目。我不明白你将如何调用 User 类的具体实现
ס
סטנלי גרונן

<强> 1。关于@Component
@Component 的作用类似于@Configuration。

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

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

Component class 需要由 Spring 自动扫描以注册 component class 的那些 bean。

<强> 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();
      }
    }

A
AzarEJ

以上答案的附加点

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

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

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

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

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

每个应用程序都需要这些

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