gpt4 book ai didi

java - 低性能计算机上的 Spring bean 单例复制

转载 作者:太空宇宙 更新时间:2023-11-04 12:11:59 24 4
gpt4 key购买 nike

所以我遇到了这个非常奇怪且令人不安的问题。在我们的低性能计算机上,一些单例 bean 在 Spring Context 初始化期间被复制。这种情况仅发生在硬件性能较低的计算机上,并且始终会发生。

到目前为止,我可以告诉的是,这似乎发生在一堆处于循环依赖关系中的类上,我怀疑它可能与 bean init 方法有关。通过 init 方法而不是构造函数将 LockScreen 注入(inject)到 MainContentPane 中,解决了循环依赖问题。

我有两份日志,一份来自正常性能计算机,一份来自低性能计算机。日志显示了差异和问题。行末尾的数字是 System.identityHashCode(object) 方法中的实例 ID。日志格式为:

LOGLEVEL  [Thread ID]  LoggingClass  Message

在正常性能的计算机上,会出现以下打印输出。

INFO  [JavaFX Application Thread]  MainContentPane      Constructor: 869589588
INFO [JavaFX Application Thread] MainContentPane Getting LockScreen In Spring Init....

INFO [JavaFX Application Thread] SessionHandler Constructor: 939274676
INFO [JavaFX Application Thread] SessionHandler Injected MainContentPane Instance: 869589588
INFO [JavaFX Application Thread] UserStateBinder Constructor: 2010765576
INFO [JavaFX Application Thread] UserStateBinder Injected SessionHandler Instance: 939274676
INFO [JavaFX Application Thread] LockScreenLockedController Constructor: 1866179042
INFO [JavaFX Application Thread] LockScreenLockedController Injected UserStateBinder Instance: 2010765576
INFO [JavaFX Application Thread] LockScreen Constructor: 204176749
INFO [JavaFX Application Thread] LockScreen Injected LockScreenLockedController Instance: 1866179042
INFO [JavaFX Application Thread] LockScreen This instance: 204176749
INFO [JavaFX Application Thread] LockScreen Bean Factory instance: 1371189401
INFO [JavaFX Application Thread] MainContentPane Injected LockScreen Instance: 204176749

此处没有重复项。

但是,如果我们查看一台低性能计算机的日志,我们可以看到初始化后创建的重复项与上面的类似。

INFO  [JavaFX Application Thread]  MainContentPane      Constructor: 22324067
INFO [JavaFX Application Thread] MainContentPane Getting LockScreen In Spring Init....

INFO [JavaFX Application Thread] SessionHandler Constructor: 32463502
INFO [JavaFX Application Thread] SessionHandler Injected MainContentPane Instance: 22324067
INFO [JavaFX Application Thread] UserStateBinder Constructor: 19793387
INFO [JavaFX Application Thread] UserStateBinder Injected SessionHandler Instance: 32463502
INFO [JavaFX Application Thread] LockScreenLockedController Constructor: 29065840
INFO [JavaFX Application Thread] LockScreenLockedController Injected UserStateBinder Instance: 19793387
INFO [JavaFX Application Thread] LockScreen Constructor: 12729388
INFO [JavaFX Application Thread] LockScreen Injected LockScreenLockedController Instance: 29065840
INFO [JavaFX Application Thread] LockScreen This instance: 12729388
INFO [JavaFX Application Thread] LockScreen Bean Factory instance: 30716643
INFO [JavaFX Application Thread] MainContentPane Injected LockScreen Instance: 12729388

INFO [JavaFX Application Thread] SessionHandler Constructor: 11043228
INFO [JavaFX Application Thread] SessionHandler Injected MainContentPane Instance: 22324067
INFO [JavaFX Application Thread] UserStateBinder Constructor: 24902967
INFO [JavaFX Application Thread] UserStateBinder Injected SessionHandler Instance: 32463502
INFO [JavaFX Application Thread] LockScreenLockedController Constructor: 17521714
INFO [JavaFX Application Thread] LockScreenLockedController Injected UserStateBinder Instance: 19793387
INFO [JavaFX Application Thread] LockScreen Constructor: 16791356
INFO [JavaFX Application Thread] LockScreen Injected LockScreenLockedController Instance: 29065840
INFO [JavaFX Application Thread] LockScreen This instance: 16791356
INFO [JavaFX Application Thread] LockScreen Bean Factory instance: 30716643

在这里我们可以看到,除了 MainContentPane 类之外,还创建了所有类的第二组实例。新的类集与前一组实例进行依赖注入(inject)(检查 id),并且 bean 工厂与之前的实例相同。

所有这些消息都打印在主线程(JavaFX 应用程序线程)上,因此似乎也不存在并发问题。

该项目还包括一个嵌入式 Jetty http 服务器。我不知道 Jetty 中是否有任何东西可能会在低性能计算机上导致此问题。

版本:

JRE(incl. JavaFX): 1.8.0.101
Spring: 4.3.3.RELEASE
Jetty + Websocket: 9.3.6.v20151106

我怀疑这个问题可能已经通过设置Spring上下文设置setAllowBeanDefinitionOverriding(false)来解决。但这也没有帮助。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setAllowBeanDefinitionOverriding(false);
context.register(ClientContext.class,
MainContext.class,
CommonContext.class,
CciContext.class,
PersistenceContext.class,
SimulatorContext.class);
context.refresh();

如果您需要任何其他信息,请告诉我,感谢您花时间帮助我。

编辑:

我现在已经确认所有初始化和所有 bean 访问都是在单个线程中发生的。我只能在跟踪日志中找到两个有趣的事实。首先,似乎所有初始化都以相同的顺序发生,即使它是完全相同的软件版本(Spring 是否并行初始化?)。其次,中等性能的计算机确实存在重复!它们仅在 UserStateBinder 类上有重复(或者可能是重新初始化?)。高性能开发计算机根本不存在这个问题。

从明天开始,我们可能会从我们的项目中删除 spring,因为我们无法找到此问题的解决方案。如果其他人希望我测试任何理论,我仍然可以使用该项目的当前版本。

最佳答案

因此,经过大量进一步的测试,我能够解决问题,但找不到奇怪行为的根本原因。

我怀疑该行为是由 Spring 初始化 bean 引起的,并且具有某种改变行为的时间依赖性。我不能确定这是否是并行性的结果。

该问题仅发生在循环依赖LockScreen -> LockScreenLockedController -> UserStateBinder -> SessionHandler -> MainContentPane -> LockScreen 中。通过将 MainContentPane 中的构造函数依赖项移至 Spring init 方法,打破了循环依赖项。代码看起来像这样。

@Bean(initMethod = "init")
public MainContentPane mainContentPane() {...}

@Bean
public LockScreen lockScreen() {...}

@Bean
public LockScreenLockedController lockScreenLockedController() {...}

@Bean
public UserStateBinder userStateBinder() {...}

@Bean
public SessionHandler sessionHandler() {...}

解决方案是在 Spring 中使用 @DependsOn 注释显式声明依赖项,如下所示。

@Bean(initMethod = "init")
public MainContentPane mainContentPane() {...}

@Bean
@DependsOn("lockScreenLockedController")
public LockScreen lockScreen() {...}

@Bean
@DependsOn("userStateBinder")
public LockScreenLockedController lockScreenLockedController() {...}

@Bean
@DependsOn("sessionHandler")
public UserStateBinder userStateBinder() {...}

@Bean
@DependsOn("mainContentPane")
public SessionHandler sessionHandler() {...}

我希望这对遇到同样问题的人有所帮助,而且我仍然很想知道为什么 Spring 会根据计算机的性能表现出这种行为。

关于java - 低性能计算机上的 Spring bean 单例复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39793687/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com