对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

使用 @Bean 注解

@Bean 是一个方法级注解,是 XML <bean/> 元素的直接对应项。 该注解支持 <bean/> 提供的一些属性,例如:spring-doc.cadn.net.cn

您可以将 @Bean 注解用于一个 @Configuration 注解的类或一个 @Component 注解的类中。spring-doc.cadn.net.cn

声明一个Bean

要声明一个Bean,您可以使用@Bean注解标注一个方法。您使用此方法在指定为方法返回值类型的ApplicationContext中注册一个Bean定义。默认情况下,Bean名称与方法名称相同。下面的示例显示了一个@Bean方法声明:spring-doc.cadn.net.cn

@Configuration
public class AppConfig {

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

	@Bean
	fun transferService() = TransferServiceImpl()
}

前面的配置与以下Spring XML完全等效:spring-doc.cadn.net.cn

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

两种声明方式都会在ApplicationContext中提供一个名为transferService的bean,该bean绑定到类型为TransferServiceImpl的对象实例,如下面的文本图像所示:spring-doc.cadn.net.cn

transferService -> com.acme.TransferServiceImpl

你也可以使用默认方法来定义 bean。这允许通过在默认方法中实现包含 bean 定义的接口来组合 bean 配置。spring-doc.cadn.net.cn

public interface BaseConfig {

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

@Configuration
public class AppConfig implements BaseConfig {

}

您还可以使用接口(或基类)返回类型来声明您的 @Bean 方法,如下例所示:spring-doc.cadn.net.cn

@Configuration
public class AppConfig {

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

	@Bean
	fun transferService(): TransferService {
		return TransferServiceImpl()
	}
}

然而,这会将高级类型预测的可见性限制为指定的接口类型(TransferService)。然后,当受影响的单例Bean被实例化后,容器才知道完整的类型(TransferServiceImpl)。非延迟加载的单例Bean根据其声明顺序进行实例化,因此你可能会看到不同的类型匹配结果,具体取决于其他组件尝试通过未声明的类型(如@Autowired TransferServiceImpl)进行匹配的时间(例如,@Autowired TransferServiceImpl仅在transferService Bean被实例化后才会解析)。spring-doc.cadn.net.cn

如果你始终通过声明的服务接口来引用你的类型,那么你的 @Bean 返回类型可以安全地遵循该设计决策。然而,对于实现多个接口的组件,或者可能通过其实现类型被引用的组件,最好声明尽可能具体的返回类型 (至少要满足引用你的 bean 的注入点所要求的级别)。

Bean 依赖

带有 @Bean 注解的方法可以具有任意数量的参数,这些参数描述了构建该 bean 所需的依赖项。例如,如果我们的 TransferService 需要一个 AccountRepository,我们可以使用方法参数来实现该依赖项,如下例所示:spring-doc.cadn.net.cn

@Configuration
public class AppConfig {

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

	@Bean
	fun transferService(accountRepository: AccountRepository): TransferService {
		return TransferServiceImpl(accountRepository)
	}
}

解析机制与基于构造函数的依赖注入几乎完全相同。有关更多详细信息,请参阅 相关部分spring-doc.cadn.net.cn

接收生命周期回调

任何使用 @Bean 注解定义的类都支持常规的生命周期回调 并且可以使用 JSR-250 的 @PostConstruct@PreDestroy 注解。有关 详细信息,请参见 JSR-250 注解spring-doc.cadn.net.cn

常规的 Spring 生命周期 回调也完全受支持。 如果一个 bean 实现了 InitializingBeanDisposableBeanLifecycle,容器会调用它们的相应方法。spring-doc.cadn.net.cn

标准的一组 *Aware 接口(如 BeanFactoryAwareBeanNameAwareMessageSourceAwareApplicationContextAware 等)也完全受支持。spring-doc.cadn.net.cn

@Bean 注解支持指定任意的初始化和销毁回调方法,类似于 Spring XML 中 init-methoddestroy-method 属性在 bean 元素上的使用,如下例所示:spring-doc.cadn.net.cn

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();
	}
}
class BeanOne {

	fun init() {
		// initialization logic
	}
}

class BeanTwo {

	fun cleanup() {
		// destruction logic
	}
}

@Configuration
class AppConfig {

	@Bean(initMethod = "init")
	fun beanOne() = BeanOne()

	@Bean(destroyMethod = "cleanup")
	fun beanTwo() = BeanTwo()
}

默认情况下,使用Java配置定义的具有公共closeshutdown 方法的bean会自动注册一个销毁回调。如果您有一个公共 closeshutdown方法,并且不希望容器关闭时调用它,可以向您的bean定义添加@Bean(destroyMethod = "")以禁用 默认的(inferred)模式。spring-doc.cadn.net.cn

对于通过JNDI获取的资源,您可能希望默认执行该操作,因为其生命周期在应用程序外部管理。请特别注意始终对DataSource执行此操作,已知在Jakarta EE应用服务器上会存在问题。spring-doc.cadn.net.cn

以下示例显示了如何防止对DataSource的自动销毁回调:spring-doc.cadn.net.cn

@Bean(destroyMethod = "")
public DataSource dataSource() throws NamingException {
	return (DataSource) jndiTemplate.lookup("MyDS");
}
@Bean(destroyMethod = "")
fun dataSource(): DataSource {
	return jndiTemplate.lookup("MyDS") as DataSource
}

此外,使用 @Bean 方法时,通常通过编程方式执行 JNDI 查找,可以使用 Spring 的 JndiTemplateJndiLocatorDelegate 辅助类,或者直接使用 JNDI InitialContext,但不使用 JndiObjectFactoryBean 变体(这会要求将返回类型声明为 FactoryBean 类型,而不是实际的目标类型,从而在其他 @Bean 方法中引用此处提供的资源时更难使用)。spring-doc.cadn.net.cn

在上面例子中的 BeanOne 的情况下,如下面的例子所示,在构造期间直接调用 init() 方法也是同样有效的:spring-doc.cadn.net.cn

@Configuration
public class AppConfig {

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

	// ...
}
@Configuration
class AppConfig {

	@Bean
	fun beanOne() = BeanOne().apply {
		init()
	}

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

指定Bean作用域

Spring 包含 @Scope 注解,以便您可以指定 bean 的作用域。spring-doc.cadn.net.cn

使用 @Scope 注解

您可以指定使用 @Bean 注解定义的 Bean 应该具有特定的作用域。您可以使用在Bean 作用域部分中指定的标准作用域中的任何一种。spring-doc.cadn.net.cn

默认作用域是 singleton,但您可以使用 @Scope 注解进行覆盖, 如下例所示:spring-doc.cadn.net.cn

@Configuration
public class MyConfiguration {

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

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

@Scopescoped-proxy

Spring 通过 作用域代理 提供了一种方便处理作用域依赖的方式。使用 XML 配置时,创建这种代理最简单的方法是 <aop:scoped-proxy/> 元素。使用 @Scope 注解在 Java 中配置您的 bean 会提供等效的支持,方法是使用 proxyMode 属性。默认值为 ScopedProxyMode.DEFAULT,通常表示除非在 component-scan 指令级别配置了不同的默认值,否则不应创建作用域代理。您可以指定 ScopedProxyMode.TARGET_CLASSScopedProxyMode.INTERFACESScopedProxyMode.NOspring-doc.cadn.net.cn

如果您将范围代理示例从 XML 参考文档(参见 作用域代理)移植到我们使用 Java 的 @Bean, 它看起来如下:spring-doc.cadn.net.cn

// an HTTP Session-scoped bean exposed as a proxy
@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;
}
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
fun userPreferences() = UserPreferences()

@Bean
fun userService(): Service {
	return SimpleUserService().apply {
		// a reference to the proxied userPreferences bean
		setUserPreferences(userPreferences())
	}
}

自定义 Bean 命名

默认情况下,配置类使用 @Bean 方法的名称作为生成的 bean 的名称。不过,可以使用 name 属性覆盖此功能,如下例所示:spring-doc.cadn.net.cn

@Configuration
public class AppConfig {

	@Bean("myThing")
	public Thing thing() {
		return new Thing();
	}
}
@Configuration
class AppConfig {

	@Bean("myThing")
	fun thing() = Thing()
}

Bean 别名

如在命名Bean中所述,有时希望给单个Bean多个名称,这通常称为Bean别名。 name属性的 @Bean注解为此目的接受一个字符串数组。下面的示例显示了如何为Bean设置多个别名:spring-doc.cadn.net.cn

@Configuration
public class AppConfig {

	@Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
	public DataSource dataSource() {
		// instantiate, configure and return DataSource bean...
	}
}
@Configuration
class AppConfig {

	@Bean("dataSource", "subsystemA-dataSource", "subsystemB-dataSource")
	fun dataSource(): DataSource {
		// instantiate, configure and return DataSource bean...
	}
}

Bean 说明

有时,提供一个更详细的bean文本描述会很有帮助。这在bean被暴露出来(可能通过JMX)用于监控目的时尤其有用。spring-doc.cadn.net.cn

要为@Bean添加描述,可以使用 @Description 注解,如下例所示:spring-doc.cadn.net.cn

@Configuration
public class AppConfig {

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

	@Bean
	@Description("Provides a basic example of a bean")
	fun thing() = Thing()
}