Arc*_*hie 8 java swing guice nullpointerexception classloader
我们有一个桌面Swing应用程序,带有Google Guice 4.1.0依赖注入.在开发过程中一切都运行良好,但是当同事试图运行应用程序时发生了一些奇怪的事情.
我们有一个MainWindow
课程延伸JPanel
.在构造函数中,此类采用一些本身可注入的控制器.在主要方法中,创建了Guice注入器.然后注入器尝试实例化MainWindow
(injector.getInstance(MainWindow.class)
).它失败了NullPointerException
!
这不会发生在我的计算机上,我们使用相同的JDK.
这里的MainWindow
类被剥离到有问题的代码(注意:不幸的是,这不会重现问题):
class MainWindow extends JPanel {
private final Foo foo;
private final JFrame frame;
@Inject
public MainWindow(Foo foo) {
super(new GridBagLayout()); // <-- NullPointerException
this.foo = foo;
this.frame = new JFrame("title");
}
public void createAndShowGUI() {
// ...
frame.add(this);
frame.pack();
frame.setVisible(true);
}
}
Run Code Online (Sandbox Code Playgroud)
这是main()
方法:
class Main {
private static final Injector injector = Guice.createInjector();
public static void main(String[] args) {
MainWindow mainWindow = injector.getInstance(MainWindow.class);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
mainWindow.createAndShowGUI();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
这是异常的堆栈跟踪:
com.google.inject.ProvisionException: Unable to provision, see the following errors:
1) Error injecting constructor, java.lang.NullPointerException
at app.gui.MainWindow.<init>(MainWindow.java:133)
while locating app.gui.MainWindow
1 error
at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1028) ~[app-1.0-SNAPSHOT.jar:?]
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1054) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main.createAndShowGUI(Main.java:40) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main.access$000(Main.java:26) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main$2.run(Main.java:67) ~[app-1.0-SNAPSHOT.jar:?]
Run Code Online (Sandbox Code Playgroud)
NPE被抛入最令人惊讶的地方 - 在调用超类的构造函数MainWindow
(这是第133行).我开始挖掘并发现手动创建MainWindow
和注入其依赖项正常工作:
MainWindow mainWindow = new MainWindow(injector.getInstance(Foo.class));
Run Code Online (Sandbox Code Playgroud)
我怀疑,也许类加载器不能正常工作,所以我既记录的类加载器试图再次MainWindow
和JPanel
:
System.out.println("MainWindow: " + MainWindow.class.getClassLoader());
System.out.println("JPanel: " + JPanel.class.getClassLoader());
MainWindow mainWindow = injector.getInstance(MainWindow.class);
Run Code Online (Sandbox Code Playgroud)
类加载器是不同的(JPanel
由引导程序加载),但现在注入工作正常.我想这是因为现在JPanel
类被显式加载到main方法上下文中.
所以我的问题是:
有关Java和OS的更多详细信息:
NullPointerException
在Windows 10,版本1511(OS Build 10586.753),JDK 1.8.0u112和1.8.0u121的同事的计算机上引发.不幸的是,我无法提供重现问题的最小版本.哎呀,我甚至无法重现这个问题,它只发生在同事的环境中.
我高度怀疑这是由于竞争条件造成的。Swing 组件不是线程安全的,应根据swing 包 javadoc在 EDT 上实例化:
Swing 的线程策略
一般来说,Swing 不是线程安全的。除非另有说明,所有 Swing 组件和相关类都必须在事件分派线程上访问。典型的 Swing 应用程序响应用户手势生成的事件进行处理。例如,单击 JButton 会通知添加到 JButton 的所有 ActionListener。由于用户手势生成的所有事件都在事件调度线程上调度,因此大多数开发人员不会受到该限制的影响。
然而,影响在于构建和显示 Swing 应用程序。对应用程序的 main 方法或 Applet 中的方法的调用不会在事件调度线程上调用。因此,在构造和显示应用程序或小程序时,必须注意将控制权转移到事件分派线程。转移控制权并开始使用 Swing 的首选方法是使用 invokeLater。invokeLater 方法安排一个 Runnable 在事件调度线程上进行处理。
(强调我的)
现在,您可以使用 启动 EDT 中的 UI invokeLater
,但是您可以在主线程上构造 UI(通过 Guice 注入器调用)。Guice 注入器调用也应该在invokeLater
启动 UI 的部分中。
归档时间: |
|
查看次数: |
277 次 |
最近记录: |