【问题标题】:Create various beans dynamically动态创建各种bean
【发布时间】:2016-12-26 12:10:50
【问题描述】:

对于当前项目,我希望具备以下能力:

“对于任何扩展接口 X 的接口,通过这个静态工厂方法创建一个 bean,使用另一个(自动装配的)bean。”

查找扩展 X 的所有接口没有问题,反射做得很好。但是我还没有找到任何方法将自己注入到 Spring 生命周期中,以便 Springs 知道这些 bean 可以存在。

目前,我正在尝试用一个简单的 bean...

@Component
public class DynamicBeanFactory {

    @Autowired
    private Service myService;

    @Autowired
    private ConfigurableListableBeanFactory beanFactory;

    protected List<Class<? extends X>> findAllSubclasses() { ... }

    @PostConstruct
    public void createOneBeanPerClass() { 
      ... create beans from findAllSubclasses(), using myService
      beanFactory.registerSingleton(name, bean);
    }
}

显然这会导致问题,例如...

@Autowired
private YextendingX dependency;

...并非一直有效,因为 Spring 无法知道 YextendingX 只有在创建 DynamicBeanFactory 之后才可用,这导致需要 @DependsOn("dynamicBeanFactory"),只是可以肯定。

那么,有没有更好的方法将 Bean(definition) 注入到生命周期中,以便使用一些工厂类创建多个 bean(definition),并能够在那里使用@Autowired。

【问题讨论】:

    标签: spring dependency-injection spring-bean


    【解决方案1】:

    玩了一段时间后,以下解决方案似乎可以解决问题...

    @Component
    public class DynamicBeanRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    
            List<Class<? extends X> classes = findAllSubclasses(); // implemented via Reflections
    
            for (Class<? extends X> clz : classes) {
    
                 RootBeanDefinition beanDefinition = new RootBeanDefinition(clz);
                 beanDefinition.setTargetType(clz);
                 beanDefinition.setFactoryBeanName("myFactoryBean");
                 beanDefinition.setFactoryMethodName("myFactoryMethod");
    
                 ConstructorArgumentValues properties = new ConstructorArgumentValues();
                 properties.addGenericArgumentValue("someString");
                 properties.addGenericArgumentValue(clz);            
                 beanDefinition.setConstructorArgumentValues(properties);
    
                 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                 beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
                 registry.registerBeanDefinition(entry.getKey(), beanDefinition );
            }   
    
        }
    etc.
    

    这样,所有 bean 似乎都被找到并作为 bean 定义添加,因此可以正确确定它们的创建顺序。为了创建它们,在 bean myFactoryBean 上调用方法 myFactoryMethod,使用所需 bean 的两个参数 "someString" 和 class clz。

    【讨论】:

      猜你喜欢
      • 2012-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-19
      相关资源
      最近更新 更多