会话范围的 bean 在错误的 ApplicationContext 中泄漏
Session-scoped bean leaks in wrong ApplicationContext
我有一个应用程序,它有 2 个 ApplicationContexts A
和 B
,其中 A
是 B
的父上下文。 B
覆盖了 A
中的一些 bean,但也使用了它的一些 bean。对于前端,我使用 Wicket,我有两个 Wicket 应用程序 AppA
和 AppB
,它们分别使用 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();
}
我有一个应用程序,它有 2 个 ApplicationContexts A
和 B
,其中 A
是 B
的父上下文。 B
覆盖了 A
中的一些 bean,但也使用了它的一些 bean。对于前端,我使用 Wicket,我有两个 Wicket 应用程序 AppA
和 AppB
,它们分别使用 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 的范围可能会有所帮助。将范围缩小到@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();
}