会话范围的 bean 在错误的 ApplicationContext 中泄漏

Session-scoped bean leaks in wrong ApplicationContext

我有一个应用程序,它有 2 个 ApplicationContexts AB,其中 AB 的父上下文。 B 覆盖了 A 中的一些 bean,但也使用了它的一些 bean。对于前端,我使用 Wicket,我有两个 Wicket 应用程序 AppAAppB,它们分别使用 Spring ApplicationContext。

现在问题出现在 Session-scoped bean sessionBean,对此我有 2 个不同的实现:A 定义了一个返回 sessionBeanA 实例的工厂方法,B 有一个具有相同签名的工厂方法返回 sessionBeanB 的实例。 用户现在打开 AppB 并且在后端,我们得到一个 sessionBeanB 的实例,无论我们在哪里注入 sessionBean,正如我们所期望的那样。 但是,如果用户现在离开 AppB 并打开 AppA(仍然使用相同的底层会话),我们将在 A 中获得一个 sessionBeanB 的实例,因为 SessionScope对象仍然持有之前创建的bean对象。

如何防止会话范围的 bean 在不同的 ApplicationContext 中泄漏? ApplicationContext A 不必为来自 B...

的 bean 烦恼

非常感谢任何帮助。

更改 Bean 的范围可能会有所帮助。将范围缩小到@conversation。

在这里您可以找到有关范围和上下文的更多信息:

https://docs.jboss.org/weld/reference/2.4.0.CR1/en-US/html/scopescontexts.html

可以通过使用 CustomScopeConfigurer 从 Spring 扩展 SessionScope 来考虑 ApplicationContext,如下所示:

import org.springframework.beans.factory.config.CustomScopeConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public final class SessionScopeConfigurer extends CustomScopeConfigurer implements ApplicationContextAware {
  private final CustomSessionScope scope;

  public SessionScopeConfigurer() {
    scope = new CustomSessionScope();
    // Overwrite the session scope added by Spring
    addScope("session", scope);
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) {
    scope.setApplicationContextId(applicationContext.getId());
  }
}

其中 CustomSessionScope 是:

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.web.context.request.SessionScope;

/**
 * Extends {@link SessionScope} by modifying all bean names, so that they are specific to their ApplicationContext.
 * This avoids session-scoped beans from context a leaking through context b.
 */
public class CustomSessionScope extends SessionScope {
  private String applicationContextId;

  public void setApplicationContextId(String applicationContextId) {
    this.applicationContextId = applicationContextId;
  }

  @Override
  public Object get(String name, ObjectFactory<?> objectFactory) {
    return super.get(modify(name), objectFactory);
  }

  @Override
  public Object remove(String name) {
    return super.remove(modify(name));
  }

  @Override
  public void registerDestructionCallback(String name, Runnable callback) {
    super.registerDestructionCallback(modify(name), callback);
  }

  private String modify(String name) {
    // Attach ApplicationContextId to the bean name
    return name + applicationContextId;
  }
}

您可以在 Java Spring 配置 class 中使用它:

@Bean
public static CustomScopeConfigurer configureSessionScope() {
  return new SessionScopeConfigurer();
}