我知道@Component
在 spring 2.5 中引入了注释,以便通过使用类路径扫描来摆脱 xml bean 定义。
@Bean
在 spring 3.0 中引入,可以用于@Configuration
完全摆脱 xml 文件并使用 java config 代替。
是否可以重复使用@Component
注释而不是引入@Bean
注释?我的理解是最终目标是在这两种情况下创建 bean。
我知道@Component
在 spring 2.5 中引入了注释,以便通过使用类路径扫描来摆脱 xml bean 定义。
@Bean
在 spring 3.0 中引入,可以用于@Configuration
完全摆脱 xml 文件并使用 java config 代替。
是否可以重复使用@Component
注释而不是引入@Bean
注释?我的理解是最终目标是在这两种情况下创建 bean。
@Component 首选 用于组件扫描和自动布线。
什么时候应该使用@Bean?
有时自动配置不是一种选择。什么时候?假设您想从 3rd-party 库中连接组件(您没有源代码,因此无法使用 @Component 注释其类),因此无法进行自动配置。
@Bean注解返回一个对象,spring 应该在应用程序上下文中注册为 bean。方法的主体包含负责创建实例的逻辑。
@Component
做@Bean
两件完全不同的事情,不要混淆。
@Component
(and @Service
and @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
。
这两种方法都旨在在 Spring 容器中注册目标类型。
区别在于@Bean
适用于方法,而@Component
适用于类型。
因此,当您使用@Bean
注释时,您可以控制方法主体中的实例创建逻辑(参见上面的示例)。使用@Component
注释你不能。
我看到了很多答案,几乎所有提到的地方@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
使现有的第三方类可用于您的 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 自动处理。
当您使用@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));
}
您有两种生成 bean 的方法。一种是创建一个带有注解的类@Component
。另一种是创建一个方法并用@Bean
. 对于那些包含方法 with 的类,@Bean
应该用注解@Configuration
一旦你运行你的 spring 项目,带有@ComponentScan
注解的类会扫描每个类@Component
,并将这个类的实例恢复到 Ioc 容器。另一件事@ComponentScan
是在其上运行方法@Bean
并将返回对象作为 bean 恢复到 Ioc 容器。因此,当您需要根据当前状态决定要创建哪种 bean 时,您需要使用@Bean
. 您可以编写逻辑并返回您想要的对象。另一件值得一提的是方法的名称,它@Bean
是bean的默认名称。
- @控制器 公共类登录控制器 { - 代码 - } - @配置 公共类 AppConfig { @豆 公共 SessionFactory sessionFactory() { - 代码 - }
创建 @Bean 是为了避免在编译时耦合 Spring 和您的业务规则。这意味着您可以在 PlayFramework 或 JEE 等其他框架中重用您的业务规则。
此外,您可以完全控制如何创建 bean,而默认 Spring 实例化是不够的。
我写了一篇文章谈论它。
https://coderstower.com/2019/04/23/factory-methods-decoupling-ioc-container-abstraction/
以上答案的附加点
假设我们有一个在多个应用程序中共享的模块,它包含一些服务。每个应用程序都不需要全部。
如果在这些服务类上使用 @Component 并在应用程序中扫描组件,
我们最终可能会检测到比必要更多的 bean
在这种情况下,您要么必须调整组件扫描的过滤,要么提供即使未使用的 bean 也可以运行的配置。否则,应用程序上下文将不会启动。
在这种情况下,最好使用 @Bean 注释并仅实例化那些 bean,
每个应用程序都需要这些
因此,本质上,使用 @Bean 将第三方类添加到上下文中。和 @Component 如果它只是在你的单个应用程序中。
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();
}
}
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 的问题。这可能有点令人困惑,但是当您开始编写更多应用程序时,它会变得非常自然。