spring – ApplicationContext registerBean自动assembly失败,但getBean在Spring 5中工作

我正在使用一个使用动态bean注册的配置类:

@Configuration public class ConfigClass { @Autowired private GenericApplicationContext applicationContext; @PostConstruct private void init() { System.out.println("init"); applicationContext.registerBean("exService", ExecutorService.class, () -> Executors.newFixedThreadPool(10), bd -> bd.setAutowireCandidate(true)); System.out.println("init done"); } } 

如果我尝试自动assemblybean,则应用程序启动失败, Field exService in com.example.DemoApplication required a bean of type 'java.util.concurrent.ExecutorService' that could not be found.出现错误Field exService in com.example.DemoApplication required a bean of type 'java.util.concurrent.ExecutorService' that could not be found.

从日志中我可以看到,在错误之前没有调用config类的init方法,因为没有打印出两个系统输出语句。

但是,当我使用applicationContext.getBean(ExecutorService.class)它确实可以正常工作。

无论如何,我可以把豆子送到Autowire?

我故意不使用@Bean注释,因为我需要根据某些条件动态注册bean。

这可能是因为您正在上下文初始化阶段注册您的bean。 如果你的目标bean在调用ConfigClass @PostConstruct之前初始化并自动连接ExecutorService ,那么就没有bean可用。

您可以尝试强制初始化顺序:

 @Component @DependsOn("configClass") public class MyComponent @Autowired private ExecutorService executorService; 

但是,使用BeanFactoryPostProcessorBeanDefinitionBuilder注册bean定义会更BeanDefinitionBuilder

 @Component public class MyBeanRegistration implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) { BeanDefinitionRegistry reg = (BeanDefinitionRegistry) bf; reg.registerBeanDefinition("exService", BeanDefinitionBuilder .rootBeanDefinition(ExecutorService.class) .setFactoryMethod("newWorkStealingPool") .getBeanDefinition()); } } 

实际上,我写了处理这些问题的小型基础设施。 以下是如何执行此操作的想法:

  • 创建一个类(让我们称之为MyClass),将ExecutorService.class作为属性封装,并将其声明为Bean(@Component)。 甚至在此之前创建一个新类将实现的接口(让我们称之为MyInterface)
  • 使用返回接口实例的方法MyInterface getInstance(String)创建一个工厂类(让我们称之为MyFactory)。 在那个工厂包括一个静态属性Map [String,MyInterface]和公共静态方法,它允许你将接口的实例添加到这个地图
  • 在MyClass中创建一个构造函数,最后将使用类名的键(“MyClass”)将新创建的自身实例放入工厂中的该映射中

现在的诀窍是,当Spring启动并初始化时,它会创建所有的bean。 当您的MyClass将被创建时,其构造函数将其实例放入工厂中。 所以现在您可以在代码中的任何地方调用:

 MyInterface myInterface = MyFactory.getInstance("MyClass"); 

你得到你的bean而不用担心实例化它。 Spring已经为你做了。 额外的额外奖励是非侵入性的 – 你不必明确地使用Spring类