此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10spring-doc.cadn.net.cn

使用@Configuration注解

@Configuration是类级注解,指示对象是 bean 定义。@Configuration类通过@Bean-注释 方法。调用@Bean方法@Configuration类也可用于定义 bean 间依赖关系。看基本概念:@Bean@Configuration进行一般介绍。spring-doc.cadn.net.cn

注入 Bean 间依赖关系

当 bean 彼此依赖时,表达这种依赖关系就像 让一个 bean 方法调用另一个 bean 方法,如以下示例所示:spring-doc.cadn.net.cn

@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通过构造函数 注射。spring-doc.cadn.net.cn

这种声明 Bean 间依赖关系的方法仅在@Bean方法 在@Configuration类。您不能声明 Bean 间依赖关系 通过使用 plain@Component类。

查找方法注入

如前所述,查找方法注入是一个 您应该很少使用的高级功能。在以下情况下,它很有用 单例范围的 Bean 依赖于原型范围的 Bean。为此使用 Java 配置类型为实现此模式提供了一种自然的方法。这 以下示例显示如何使用查找方法注入:spring-doc.cadn.net.cn

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()方法被覆盖,以便它查找新的 (prototype) 命令对象。以下示例显示了如何执行此作:spring-doc.cadn.net.cn

@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 的配置如何在内部工作的更多信息

请考虑以下示例,其中显示了@Beanannotated 方法被调用两次:spring-doc.cadn.net.cn

@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并返回它,你会 通常期望有两个实例(每个服务一个)。那肯定是 problemacy:在 Spring 中,实例化的 bean 有一个singleton默认范围。这是 神奇之处:全部@Configuration类在启动时被子类化 跟CGLIB.在子类中,子方法首先检查容器中是否有任何 缓存(作用域)bean,然后调用父方法并创建一个新实例。spring-doc.cadn.net.cn

根据 Bean 的范围,行为可能会有所不同。我们正在谈论 关于单身人士在这里。

没有必要将 CGLIB 添加到类路径中,因为 CGLIB 类是重新打包的 在org.springframework.cglib包,并直接包含在spring-core罐。spring-doc.cadn.net.cn

由于 CGLIB 在startup-time 动态添加功能,因此存在一些限制。特别是,配置类不能是最终的。但是,任何构造函数都允许在配置类上使用,包括使用@Autowired或单个非默认构造函数声明,用于默认注入。spring-doc.cadn.net.cn

如果您希望避免 CGLIB 施加的任何限制,请考虑声明您的@Bean关于非@Configuration类(例如,在普通@Component类 相反),或者通过使用@Configuration(proxyBeanMethods = false). 之间的跨方法调用@Bean方法 然后不会被拦截,因此您必须完全依赖构造函数或方法级别的依赖注入。spring-doc.cadn.net.cn