在我的应用程序中,它不是 Web 服务应用程序,因此不提供休息端点,我使用注入的
BeanContext
在需要时创建其他 bean 的实例。这些豆子是@Prototype
豆子,而不是@Singleton
,因为它们应该只在需要时存在,并在使用后丢弃。
代码在 micronaut 3.6.3 上运行良好,但是当我升级到 4.2.2 时,注入的 BeanContext 找不到任何 bean。
beanContext.getBean(ProtoTypeBean.class);
会抛出 NoSuchBeanException
为了澄清我的意思,我在 我的 github 存储库中有一个可重现的案例。
代码的简化版本如下所示:
主应用程序启动
ApplicationContext
,它创建 ScheduleReader 的实例并调用 run()
public static void main(String[] args) {
try (final ApplicationContext context = ApplicationContext.run()) {
context.getBean(ScheduleReader.class).run();
}
}
在
ScheduleReader.run()
方法中,我使用注入的BeanContext
来创建另一个Bean的实例
@Singleton
@Slf4j
public class ScheduleReader implements Runnable {
private final BeanContext beanContext;
@Inject
ScheduleReader(final BeanContext beanContext) {
this.beanContext = beanContext;
}
@Override
public void run() {
beanContext.getBean(Action.class).run();
}
}
Action
也是一个@Prototype
,但此时,我得到以下异常:
12:22:29.946 [pool-1-thread-1] ERROR com.example.ScheduleReader - Error while starting Action: No bean of type [com.example.Action] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [com.example.Action] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
at io.micronaut.context.DefaultBeanContext.newNoSuchBeanException(DefaultBeanContext.java:2773)
at io.micronaut.context.DefaultApplicationContext.newNoSuchBeanException(DefaultApplicationContext.java:304)
at io.micronaut.context.DefaultBeanContext.resolveBeanRegistration(DefaultBeanContext.java:2735)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1729)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:856)
at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:848)
at com.example.ScheduleReader.runPlanner(ScheduleReader.java:41)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
当我在
ApplicationContext.run()
中使用另一个 ScheduleReader
时,我可以使用该应用程序上下文来检索其他 bean,但我无法想象您现在每次想要创建 bean 的新实例时都必须启动 ApplicationContexts...
Micronaut 指南专注于使用其余控制器启动应用程序,但如上所述,这只是一个不公开端点的独立应用程序。我在迁移指南中也没有找到任何有关更改内容或如何解决此问题的线索。
我错过了什么?
我认为这是因为你调用了 getBean() 而不是 createBean()。 get 方法适用于 ApplicationContext,因为应用程序上下文最初会实例化所有 bean,但 beancontext 会延迟加载它们。如果您查看 getBean() 的实现并遵循方法调用,您将在 DefaultBeanContext.java 中找到以下方法:
@NonNull
public <T> T getBean(@Nullable BeanResolutionContext resolutionContext,
@NonNull Argument<T> beanType,
@Nullable Qualifier<T> qualifier) {
ArgumentUtils.requireNonNull("beanType", beanType);
return resolveBeanRegistration(resolutionContext, beanType, qualifier, true).bean;
最后一行抛出异常。