0

我正在尝试使用 Weld-SE 引导一个小型 javafx 应用程序。@Inject如果我删除注释Menubar并手动实例化它,我就能够运行应用程序。但是在我添加@Inject 的那一刻,应用程序抛出异常。下面列出的是注入点和生产者方法。这就是我所做的所有配置,我错过了什么吗?

注入点

@Inject MenuBar menuBar

具有生产者方法的类

public class ComponentProducer {

    @Produces
    public MenuBar createMenuBar(){
        return new MenuBar();
    }

}

例外

    491 [JavaFX Application Thread] INFO org.jboss.weld.Bootstrap - WELD-000101 Transactional services not available. Injection of @Inject UserTransaction not available.    Transactional observers will be invoked synchronously.
    8868 [JavaFX Application Thread] WARN org.jboss.interceptor.model.InterceptionTypeRegistry - Class 'javax.ejb.PostActivate' not found, interception based on it is not enabled
    8868 [JavaFX Application Thread] WARN org.jboss.interceptor.model.InterceptionTypeRegistry - Class 'javax.ejb.PrePassivate' not found, interception based on it is not enabled
    Exception in Application start method
    Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:399)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:47)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:115)
at java.lang.Thread.run(Thread.java:722)

    Caused by: java.lang.NullPointerException
at net.sourceforge.squirrel_sql.client.MainScene.<init>(MainScene.java:26)
at net.sourceforge.squirrel_sql.client.FXApplication.startup(FXApplication.java:176)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:304)
at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:54)
at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:163)
at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:298)
at org.jboss.weld.introspector.jlr.WeldMethodImpl.invokeOnInstance(WeldMethodImpl.java:200)
at org.jboss.weld.introspector.ForwardingWeldMethod.invokeOnInstance(ForwardingWeldMethod.java:59)
at org.jboss.weld.injection.MethodInjectionPoint.invokeOnInstanceWithSpecialValue(MethodInjectionPoint.java:194)
at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:241)
at org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:216)
at org.jboss.weld.manager.BeanManagerImpl.notifyObservers(BeanManagerImpl.java:654)
at org.jboss.weld.manager.BeanManagerImpl.fireEvent(BeanManagerImpl.java:647)
at org.jboss.weld.manager.BeanManagerImpl.fireEvent(BeanManagerImpl.java:641)
at org.jboss.weld.event.EventImpl.fire(EventImpl.java:93)
at net.sourceforge.squirrel_sql.client.Main.start(Main.java:180)
at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:315)
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:174)
at com.sun.javafx.application.PlatformImpl$3.run(PlatformImpl.java:141)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication$2$1.run(GtkApplication.java:79)
... 1 more
4

3 回答 3

1

是因为您试图在构造函数或初始化程序块中使用 menuBar 吗?

如果是这样,请尝试使用 Initializable 并在初始化中使用它们。

于 2013-02-02T01:01:30.367 回答
1

ShaggyInjun,您指的是Initializable接口,它表明您正在尝试与FXMLLoader集成。以下所有信息均假设您使用 FXML 进行接口定义,并且仅讨论将值注入 FXML 控制器的问题。

FXMLLoader具有控制器工厂的概念,您应该使用它来将控制器实例化与您的依赖注入系统集成。在 Oracle 的Mastering FXML Tutorial中有一个关于控制器工厂的简短讨论。Andy在他的博客中为 Guice 演示了这样一个工厂的定义,并且在 github 上有一个Guice 在 FXML 中的全面集成。


对于 Weld,您将需要实现类似的控制器工厂回调机制来实现 Weld 提供的依赖注入功能。您在评论中链接的 Matthieu Brouillard 的文章FXML & JavaFX—Fueled by CDI & JBoss Weld似乎提供了初始化 Weld 和将 Weld 接口到 FXMLLoader 控制器工厂机制所需的所有信息。具体来说,以下代码是 Andy Till 基于 FXML 的注入机制的 Weld 等效代码:

public class FXMLLoaderProducer {
  @Inject Instance<Object> instance;
  @Produces public FXMLLoader createLoader() {
    FXMLLoader loader = new FXMLLoader();
    loader.setControllerFactory(new Callback<Class<?>, Object>() {
      @Override public Object call(Class<?> param) {
        return instance.select(param).get();
      }
    });
    return loader;
  }
}

即使使用了 FXMLoader 控制器工厂,我相信是 FXMLLoader 正在实例化控制器。因此,在这些情况下,您不应该使用注释,@PostConstruct因为它们仅在依赖注入系统维护对象的生命周期时才适用——如果 FXMLLoader 创建控制器则情况并非如此。

还有另一种选择,即使用setController显式设置 FXMLLoader 使用的控制器。这将允许您让您的依赖注入系统使用它希望的任何方式实例化(并注入)控制器,然后您可以随后将实例化的控制器传递给您的 FXMLLoader。在这种情况下,像这样的注释@PostConstruct应该可以工作,因为依赖注入系统现在正在维护对象的生命周期(并且@PostConstruct将在创建控制器之后和将控制器传递给 FXMLLoader 之前由依赖注入系统调用)。


我将在此处发布基于 Andy 的 Guice 解决方案,因为它是一个小而简单的示例,说明如何在 Guice 中完成类似的注入(以防他的博客离线):

class GuiceControllerFactory implements Callback<Class<?>, Object> {
  private final Injector injector;
  public GuiceControllerFactory(Injector anInjector) {
    injector = anInjector;
  }     
  @Override public Object call(Class<?> aClass) {
    return injector.getInstance(aClass);
  }
}
于 2013-02-13T21:02:04.077 回答
0

EJB 文档指出,使用 @PostConstruct 注释的方法将在注入完成后调用,这是预期变量注入的方法。

@PostConstruct

The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization.

然而,期望变量在内部初始化initialize似乎确实有效。

根据 Initializable 文档,initialize 是Called to initialize a controller after its root element has been completely processed. Initializable

初始化和@PostConstruct 的调用顺序

我认为可以安全地理解初始化的调用与对象构造没有任何关系。相反,initialize 在当前节点图的根已被完全处理时调用,因此可以处理诸如事件处理程序等之类的document.onload东西jQuery(document).ready()。如果您要在对象图准备好之前尝试附加事件处理程序,则很有可能会看到空指针,因为该节点不是对象图,因此无法附加事件处理程序。

因此,在将对象加载到场景图之前,您将实例化一个对象(直接或通过注入)。因此 @PostConstruct 在初始化之前被调用。但是,如果您直接实例化对象,那么调用注解 @PostConstruct 的方法的责任就落在了您身上,否则不会发生后期处理。

结论:可以肯定的是,initialize 总是在使用 @PostConstruct 注释的方法之后调用。

编辑

@Jewelsea 指出了一些我没有在上面列出的假设。所以就在这里,上面对我有用的情况。

  • 将 FXML 文件用于视图。
  • 在 fxml 文件中指定的控制器名称。
于 2013-02-13T20:13:06.117 回答