|
对于最新的稳定版本,请使用 Spring Framework 7.0.6! |
使用 @Configuration 注解
@Configuration 是一个类级别注解,表示该对象是 bean 定义的来源。 @Configuration 类通过 @Bean 注解的方法声明 bean。 对 @Configuration 类上的 @Bean 方法的调用也可以用于定义 bean 之间的依赖关系。 有关一般性介绍,请参见 基本概念: @Bean 和 @Configuration。
注入Bean间的依赖
当bean之间存在依赖关系时,表达这种依赖关系非常简单,只需让一个bean方法调用另一个bean方法即可,如下例所示:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
return new BeanOne(beanTwo());
}
@Bean
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
@Configuration
class AppConfig {
@Bean
fun beanOne() = BeanOne(beanTwo())
@Bean
fun beanTwo() = BeanTwo()
}
在前面的示例中,通过构造函数注入,beanOne 接收到对 beanTwo 的引用。
这种声明bean间依赖的方法仅在@Bean方法被声明在@Configuration类中时才有效。你不能通过使用普通的@Component类来声明bean间的依赖。 |
查找方法注入
如前所述,查找方法注入是一个高级功能,应很少使用。当单例作用域的bean依赖于原型作用域的bean时,它很有用。使用Java进行此类配置可以自然地实现此模式。下面的示例显示了如何使用查找方法注入:
-
Java
-
Kotlin
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}
abstract class CommandManager {
fun process(commandState: Any): Any {
// grab a new instance of the appropriate Command interface
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.setState(commandState)
return command.execute()
}
// okay... but where is the implementation of this method?
protected abstract fun createCommand(): Command
}
通过使用Java配置,您可以创建一个继承自CommandManager的子类,其中抽象的createCommand()方法被重写,以便查找一个新的(原型)命令对象。下面的示例显示了如何操作:
-
Java
-
Kotlin
@Bean
@Scope("prototype")
public AsyncCommand asyncCommand() {
AsyncCommand command = new AsyncCommand();
// inject dependencies here as required
return command;
}
@Bean
public CommandManager commandManager() {
// return new anonymous implementation of CommandManager with createCommand()
// overridden to return a new prototype Command object
return new CommandManager() {
protected Command createCommand() {
return asyncCommand();
}
}
}
@Bean
@Scope("prototype")
fun asyncCommand(): AsyncCommand {
val command = AsyncCommand()
// inject dependencies here as required
return command
}
@Bean
fun commandManager(): CommandManager {
// return new anonymous implementation of CommandManager with createCommand()
// overridden to return a new prototype Command object
return object : CommandManager() {
override fun createCommand(): Command {
return asyncCommand()
}
}
}
有关Java基于配置如何在内部工作的更多信息
考虑以下示例,其中显示了一个带有 @Bean 注解的方法被调用两次:
-
Java
-
Kotlin
@Configuration
public class AppConfig {
@Bean
public ClientService clientService1() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
@Bean
public ClientService clientService2() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
@Bean
public ClientDao clientDao() {
return new ClientDaoImpl();
}
}
@Configuration
class AppConfig {
@Bean
fun clientService1(): ClientService {
return ClientServiceImpl().apply {
clientDao = clientDao()
}
}
@Bean
fun clientService2(): ClientService {
return ClientServiceImpl().apply {
clientDao = clientDao()
}
}
@Bean
fun clientDao(): ClientDao {
return ClientDaoImpl()
}
}
clientDao() 在 clientService1() 和 clientService2() 中各被调用了一次。
由于此方法会创建一个新的 ClientDaoImpl 实例并返回它,你通常会期望有两个实例(每个服务一个)。这显然会带来问题:在 Spring 中,实例化的 bean 默认具有 singleton 范围。这就是神奇之处:所有 @Configuration 类在启动时都会被 CGLIB 所继承。在子类中,子方法会先检查容器中是否有缓存(作用域)的 bean,然后再调用父方法并创建一个新的实例。
| 该行为可能根据你的 bean 的作用域不同而有所差异。我们这里讨论的是单例模式。 |
|
不需要将CGLIB添加到类路径中,因为CGLIB类已在 |
|
由于CGLIB在启动时动态添加特性,存在一些限制。具体而言,配置类不能是final类。然而,配置类允许使用任何构造函数,包括使用 如果您希望避免CGLIB带来的限制,可以考虑在非 |