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

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

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


当前回答

@Component auto detects and configures the beans using classpath scanning whereas @Bean explicitly declares a single bean, rather than letting Spring do it automatically. @Component does not decouple the declaration of the bean from the class definition where as @Bean decouples the declaration of the bean from the class definition. @Component is a class level annotation whereas @Bean is a method level annotation and name of the method serves as the bean name. @Component need not to be used with the @Configuration annotation where as @Bean annotation has to be used within the class which is annotated with @Configuration. We cannot create a bean of a class using @Component, if the class is outside spring container whereas we can create a bean of a class using @Bean even if the class is present outside the spring container. @Component has different specializations like @Controller, @Repository and @Service whereas @Bean has no specializations.

其他回答

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

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

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

假设我想要特定的实现依赖于某种动态状态。 @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和@Bean做两件完全不同的事情,不应该混淆。

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

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

回答你的问题…

是否有可能重用@Component注释而不是引入@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自动处理。

当您使用@Component标记时,这与使用带有香草bean声明方法(用@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));
}