【问题标题】:Spring Boot Factory Bean Creation OrderSpring Boot 工厂 Bean 创建顺序
【发布时间】:2019-04-03 23:43:09
【问题描述】:

我正在尝试在 Spring Boot 中动态注册 Bean,但是如果尝试自动装配其中一个动态 bean,则创建 bean 的顺序总是会导致 NoSuchBeanDefinitionException

我的设置包括两个项目,一个 spring-boot-starter 项目和实际的 spring-boot 应用程序。

实际的应用程序注册了一个BeanDefinitionRegistryPostProcessor,它添加了 bean 定义。实例本身是通过在启动项目中定义的另一个 bean 构建的,该项目本身将另一个 bean 作为依赖项。

为了使用动态注册的 bean,我创建了一个用 @Component 注释的类,并定义了一个期望该 bean 作为参数的构造函数。 当我通过设置@Autowired(required=false) 调试应用程序时,我可以看到在创建动态bean 之前调用了我的组件的构造函数。而且,当时连工厂 bean 都没有创建。

将带有工厂 bean 名称的 @DependsOn 添加到组件导致首先创建工厂,而不是动态 bean。

使用动态 bean 的名称设置 @DependsOn 有效,但这似乎不是解决此问题的正确方法。

为什么 Spring 以错误的顺序创建我的 bean,我能做些什么来解决这个问题?

编辑:

我能够在示例存储库中重现该问题:
https://github.com/maveeee/spring-dynamic-bean-demo/

【问题讨论】:

    标签: java spring spring-boot spring-boot-starter


    【解决方案1】:

    您可以使用@Order 注释来定义带注释的组件或bean 的排序顺序。

    考虑到在 Spring 4.0 之前,这个注解只用于 AspectJ 的执行顺序。 Spring 4.0 之后,支持将注入的组件排序到集合中。因此,Spring 会根据它们的 order 值注入相同类型的自动装配 bean。

    例如:

    interface IBean {
        String getName();
    }
    
    public class BeanX implements IBean {
        public BeanX() {}
    
        @Override
        public String getName() {
            return "BeanX";
        }
    }
    
    public class BeanY implements IBean {
        public BeanY() {}
    
        @Override
        public String getName() {
            return "BeanY";
        }
    }
    
    @Component
    public class RandomComponent {
        @Autowired
        private List<IBean> beans;
    
        @PostConstruct
        public void getBeanValues() {
            System.out.println("\n---@Bean---\n");
            for (IBean b : beans) {
                System.out.println(b.getName());
            }
        }
    
        @Bean
        @Order(1)
        public IBean getBeanX() {
            return new BeanX();
        }
    
        @Bean
        @Order(0)
        public IBean getBeanY() {
            return new BeanY();
        }
    }
    

    将打印:

    ---@Bean---
    
    BeanY
    BeanX
    

    因为BeanY 的优先级(0,较低的值)高于 BeanX(较高的值,1)。

    GitHub Demo

    相关文章:

    【讨论】:

    • 我将提取相关部分并设置一个演示库
    • @MaVe 不客气 :) 如果您最终能够重现该问题,请不要犹豫,在这里给我留言,我会尽力帮助您。
    • 我终于可以重现这个问题了:可以在github.com/maveeee/spring-dynamic-bean-demo看到一个示例
    • @MaVe 有机会时请检查此pull request 以查看它是否解决了您的问题,如果解决了问题,请告诉我,以便我为未来的读者更新答案。跨度>
    • @MaVe 是的,确实!检查这个:stackoverflow.com/a/41444078/5640649
    【解决方案2】:

    我发现我的问题是由我创建 bean 定义的方式引起的。我使用的是GenericBeanDefinition 而不是RootBeanDefinition。使用后者允许我使用setTargetType() 而不是setBeanClass(),这立即解决了问题并导致Spring 找出创建bean 的正确顺序,以便我可以通过@Autowired 注入动态创建的bean。

    之前:

            var identifier = ...    // Some String identifying the bean
            var clazz = ...         // Some class object coming from a dependency
    
            var beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClass(clazz);
            beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
            beanDefinition.setAutowireCandidate(true);
            beanDefinition.setFactoryBeanName(CONTRACT_FACTORY_BEAN_NAME);
            beanDefinition.setFactoryMethodName(CONTRACT_FACTORY_METHOD_NAME);
    
            registry.registerBeanDefinition(identifier, beanDefinition);
    

    之后:

            var identifier = ...    // Some String identifying the bean
            var clazz = ...         // Some class object coming from a dependency
    
            var beanDefinition = new RootBeanDefinition();
            beanDefinition.setTargetType(clazz);
            beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
            beanDefinition.setAutowireCandidate(true);
            beanDefinition.setFactoryBeanName(CONTRACT_FACTORY_BEAN_NAME);
            beanDefinition.setFactoryMethodName(CONTRACT_FACTORY_METHOD_NAME);
    
            registry.registerBeanDefinition(identifier, beanDefinition);
    

    我将更新repository中的示例代码以供进一步参考。

    【讨论】:

      猜你喜欢
      • 2019-12-25
      • 1970-01-01
      • 2016-07-05
      • 2018-06-26
      • 1970-01-01
      • 1970-01-01
      • 2021-02-11
      • 1970-01-01
      • 2016-01-19
      相关资源
      最近更新 更多