如何在 Spring 中按类型创建一个 bean?
How to create a bean by type in Spring?
在我的 ApplicationContext 中,我创建了几个相同样式的 Bean。所以我有很多复制的代码为每个 bean 写一个 FactoryBean
。这些 bean 有一个共同点,实现所有一个特殊接口。
我想将所有的 bean 创建移动到一个工厂。那个人必须提供这样的方法
<T extends CommonInterface> T createInstance(Class<T> clazz);
在那里我可以实现创建我的特殊 bean 之一所需的所有实例化。
我的实现将由 spring 为
调用
@Autowired
private MyCommonInterfaceImplementation impl;
那样
createInstance(MyCommonInterfaceImplementation.class)
到目前为止,我查看了 BeanFactory
和 FactoryBean
,这两个似乎都不是我要搜索的。
有什么建议吗?
为什么不用@bean
@Bean
public MyCommonInterfaceImplementation getMyCommonInterfaceImplementation(){
return MyBeanFactory.createInstance(MyCommonInterfaceImplementation.class);
}
//should autowire here
@Autowired
private MyCommonInterfaceImplementation impl;
从 Spring 4.3 开始,您不再需要注释 bean 类,您可以让它们通过 componentscan 实例化。
@Configuration
@ComponentScan(
value = "some.package.path",
includeFilters = {
@Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
这实际上为此处列出的三个 类 创建了 bean。该示例也应该在没有过滤器的情况下工作(包中的所有内容都变成一个 bean)。只要 类 有一个可用于自动装配的构造函数,它就可以工作。我认为不可能过滤特定接口的所有实现,然后注册一个 bean。
为此,您可以使用 ContextListener
做一些事情,例如使用反射找出要实例化的 类 ,然后使用 context.autowire(..) 从您的上下文中注入任何依赖项。有点 hacky,但它可能会工作。
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
MyClass bean
= context
.getAutowireCapableBeanFactory()
.autowire(MyClass.class, Autowire.BY_NAME.value(), true);
...
}
当然还有如何在上下文中注册bean的问题。
您也许还可以调整 this SO question 关于如何以编程方式添加 bean 的答案。
基本上,只有在创建 bean 期间需要一些特殊处理时,才需要在 "factory" 上使用 @Bean
注释。
如果一切都可以 @Autowired
,通过设置器、字段或一个构造函数,并且在初始化期间不需要对 bean 执行任何其他操作,您可以简单地声明注释 @Component
接口的每个实现。只要您的应用程序中有 component scanning
处于活动状态,它就可以工作。结果将是每个组件 spring 将创建一个您可以使用的 bean。
我是在手机上写的,所以显示代码不是最好的。只需按照 @ComponentScan
上的一些教程进行操作,或者如果您需要,请告诉我,我可以通过示例来补充这个答案。
最后,我发现的最佳方法是使用 ConfigurationClassPostProcessor
。例如,我使用了 https://github.com/rinoto/spring-auto-mock
但是,由于从无到有创建 bean 非常复杂并且 "too much magic",我们决定通过 @Bean
.
显式创建这些 bean
感谢您的回答。
在我的 ApplicationContext 中,我创建了几个相同样式的 Bean。所以我有很多复制的代码为每个 bean 写一个 FactoryBean
。这些 bean 有一个共同点,实现所有一个特殊接口。
我想将所有的 bean 创建移动到一个工厂。那个人必须提供这样的方法
<T extends CommonInterface> T createInstance(Class<T> clazz);
在那里我可以实现创建我的特殊 bean 之一所需的所有实例化。
我的实现将由 spring 为
调用@Autowired
private MyCommonInterfaceImplementation impl;
那样
createInstance(MyCommonInterfaceImplementation.class)
到目前为止,我查看了 BeanFactory
和 FactoryBean
,这两个似乎都不是我要搜索的。
有什么建议吗?
为什么不用@bean
@Bean
public MyCommonInterfaceImplementation getMyCommonInterfaceImplementation(){
return MyBeanFactory.createInstance(MyCommonInterfaceImplementation.class);
}
//should autowire here
@Autowired
private MyCommonInterfaceImplementation impl;
从 Spring 4.3 开始,您不再需要注释 bean 类,您可以让它们通过 componentscan 实例化。
@Configuration
@ComponentScan(
value = "some.package.path",
includeFilters = {
@Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
这实际上为此处列出的三个 类 创建了 bean。该示例也应该在没有过滤器的情况下工作(包中的所有内容都变成一个 bean)。只要 类 有一个可用于自动装配的构造函数,它就可以工作。我认为不可能过滤特定接口的所有实现,然后注册一个 bean。
为此,您可以使用 ContextListener
做一些事情,例如使用反射找出要实例化的 类 ,然后使用 context.autowire(..) 从您的上下文中注入任何依赖项。有点 hacky,但它可能会工作。
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
MyClass bean
= context
.getAutowireCapableBeanFactory()
.autowire(MyClass.class, Autowire.BY_NAME.value(), true);
...
}
当然还有如何在上下文中注册bean的问题。
您也许还可以调整 this SO question 关于如何以编程方式添加 bean 的答案。
基本上,只有在创建 bean 期间需要一些特殊处理时,才需要在 "factory" 上使用 @Bean
注释。
如果一切都可以 @Autowired
,通过设置器、字段或一个构造函数,并且在初始化期间不需要对 bean 执行任何其他操作,您可以简单地声明注释 @Component
接口的每个实现。只要您的应用程序中有 component scanning
处于活动状态,它就可以工作。结果将是每个组件 spring 将创建一个您可以使用的 bean。
我是在手机上写的,所以显示代码不是最好的。只需按照 @ComponentScan
上的一些教程进行操作,或者如果您需要,请告诉我,我可以通过示例来补充这个答案。
最后,我发现的最佳方法是使用 ConfigurationClassPostProcessor
。例如,我使用了 https://github.com/rinoto/spring-auto-mock
但是,由于从无到有创建 bean 非常复杂并且 "too much magic",我们决定通过 @Bean
.
感谢您的回答。