1.12.3. 使用@Bean

@Bean是一个方法级注释,是xml <bean/>元素的直接模拟,支持<bean/>提供的一些属性,例如: init-method 、destroy-method 、 autowiring 、 name
可以在带@Configuration注释的类或带@Component注释的类中使用@Bean注释。
声明一个bean
要声明bean,可以使用@Bean注释对方法进行注释。您可以使用此方法在指定为方法返回值的类型的ApplicationContext中注册bean定义。默认情况下,bean名称与方法名称相同。下面的示例显示了@Bean方法声明:

@Configuration
public class AppConfig {

    @Bean
    public TransferServiceImpl transferService() {
        return new TransferServiceImpl();
    }
}

相应XML:

<beans>
    <bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>

这两个声明都使一个名为transferServicee的bean在应用程序上下文中可用,绑定到TransferServiceImpl类型的对象实例,如下文本图像所示:

transferService -> com.acme.TransferServiceImpl

还可以使用接口(或基类)返回类型来声明@Bean方法,如下例所示:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

Bean依赖
@Bean注释的方法可以有任意数量的参数来描述构建该bean所需的依赖关系。例如,如果TransferService需要一个 AccountRepository,我们可以用一个方法参数实现这种依赖关系,如下例所示:

@Configuration
public class AppConfig {

    @Bean
    public TransferService transferService(AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }
}

解析机制与基于构造函数的依赖注入非常相似。有关详细信息,请参阅相关部分。
接收生命周期回调
用@Bean注释定义的任何类都支持常规的生命周期回调,并且可以使用JSR-250中的@PostConstruct和@PreDestroy注释。更多详细信息,请参见JSR-250注释。

还完全支持常规的Spring生命周期回调。如果bean实现了InitialingBean、DisposableBean或Lifecycle,那么容器将调用它们各自的方法。

还完全支持*Aware接口的集(如BeanFactoryAware、BeannameAware、MessageSourceAware、ApplicationContextAware等)。

@Bean注释支持指定任意的初始化和销毁回调方法,很像spring xml中bean元素的init-method和destroy-method属性,如下例所示:

public class BeanOne {

    public void init() {
        // initialization logic
    }
}

public class BeanTwo {

    public void cleanup() {
        // destruction logic
    }
}

@Configuration
public class AppConfig {

    @Bean(initMethod = "init")
    public BeanOne beanOne() {
        return new BeanOne();
    }

    @Bean(destroyMethod = "cleanup")
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}
默认情况下,使用具有public close或shutdown方法的Java配置定义的bean将自动加入销毁回调。如果您有一个public close 或 shutdown方法,并且不希望在容器关闭时调用它,则可以将@Bean(destroyMethod="") 添加到bean定义中,以禁用默认(推断)模式。
默认情况下,您可能希望为使用JNDI获取的资源执行此操作,因为它的生命周期是在应用程序外部管理的。特别是,确保对数据源总是这样做,因为它在JavaEE应用服务器上是有问题的。
下面的示例演示如何防止数据源的自动销毁回调:
@Bean(destroyMethod="") public DataSource dataSource() throws NamingException { return (DataSource) jndiTemplate.lookup("MyDS"); }
另外,对于@Bean方法,您通常使用编程的JNDI查找,或者使用Spring的JndiTemplate或JndiLocatorDelegate帮助器,或者直接使用JNDI InitialContext,但不使用JndiObjectFactoryBean变量(这将强制您将返回类型声明为FactoryBean类型,而不是实际的目标类型,这使得在其他@Bean方法中使用交叉引用调用变得更加困难,这些方法打算在此处引用所提供的资源)。

对于上述示例中的BeanOne,在构造期间直接调用init() 方法同样有效,如下示例所示:

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        BeanOne beanOne = new BeanOne();
        beanOne.init();
        return beanOne;
    }

    // ...
}

当你直接在Java中工作时,你可以用你的对象做任何事情,并不总是需要依赖于容器的生命周期。

指定bean范围
Spring包含@Scope注释,这样您就可以指定bean的作用域。

使用@Scope注释
您可以指定用@Bean注释定义的bean应该具有特定的作用域。默认范围是singleton,但是可以用@Scope注释覆盖它,如下示例所示:

@Configuration
public class MyConfiguration {

    @Bean
    @Scope("prototype")
    public Encryptor encryptor() {
        // ...
    }
}

@Scope和scoped代理
Spring提供了一种通过作用域代理来处理作用域依赖项的方便方法。在使用XML配置时,创建此类代理的最简单方法是<aop:scoped-proxy/>元素。用JavaScript注释在Java中配置bean可以提供与 <aop:scoped-proxy/> 属性等价的支持。默认值为no (ScopedProxyMode.NO),但可以指定ScopedProxyMode.TARGET_CLASS 或ScopedProxyMode.INTERFACES。

如果将具有范围的代理示例从XML引用文档(参见范围代理)导入到使用Java的“bean”,则类似于以下内容:

// 作为代理公开的HTTP会话范围的bean
@Bean
@SessionScope
public UserPreferences userPreferences() {
    return new UserPreferences();
}

@Bean
public Service userService() {
    UserService service = new SimpleUserService();
    // a reference to the proxied userPreferences bean
    service.setUserPreferences(userPreferences());
    return service;
}

自定义bean命名
默认情况下,配置类使用@Bean方法的名称作为结果bean的名称。但是,可以使用name属性覆盖此功能,如下示例所示:

@Configuration
public class AppConfig {

    @Bean(name = "myThing")
    public Thing thing() {
        return new Thing();
    }
}

bean别名
有时需要为单个bean指定多个名称,可以用为bean别名。@Bean注释的name属性为此接受一个字符串数组。下面的示例演示如何为bean设置多个别名:

@Configuration
public class AppConfig {

    @Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
    public DataSource dataSource() {
        // 实例化、配置并返回数据源bean…
    }
}

Bean描述
有时,提供一个更详细的bean文本描述会有所帮助。当bean暴露(可能通过jmx)用于监视时,这尤其有用。
要向@Bean添加描述,可以使用@Description注释,如下示例所示:

@Configuration
public class AppConfig {

    @Bean
    @Description("Provides a basic example of a bean")
    public Thing thing() {
        return new Thing();
    }
}