gpt4 book ai didi

java - 无法在 session 超时时获取 session 范围的 bean

转载 作者:行者123 更新时间:2023-11-30 07:23:32 25 4
gpt4 key购买 nike

我需要在 HttpSessionListener.sessionDestroyed() 上获得一个代理 session 范围的 bean。目标是在 session 被销毁时(通过 invalidate() 或超时)进行 session 清理。我添加了 ContextLoaderListener 来公开上下文并通过 WebApplicationContextUtils.getWebApplicationContext() 获取 bean。

如果我自己在 Servlet 中使 session 无效,一切正常,但是当 session 超时时,我得到一个 Scope 'session' is not active for the current thread;。我知道问题的发生是因为清理是由 Servlet 引擎的内部线程完成的,但我仍然需要能够从 HttpSessionListener 获取这个 bean。

我遇到了很多相同的问题,没有人有解决方案,这就是我再次提问的原因。

我的 applicationContext.xml 没有 bean 声明,因为我正在使用注释。

这是 session 超时时我需要访问的bean:

@Component
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class Access {

static private int SERIAL = 0;
private int serial;

public Access() {
serial = SERIAL++;
}

public int getSerial() {
return serial;
}
}

这是手动创建销毁 session 的 Controller

@Controller
public class Handler {

@Autowired
Access access;


@RequestMapping("/create")
public @ResponseBody String create() {
return "Created "+access.getSerial();
}

@RequestMapping("/destroy")
public @ResponseBody String destroy(HttpSession sess) {
int val = access.getSerial();
sess.invalidate();
return "Destroyed "+val;
}

}

这是监听 session 销毁的 HttpSessionListener我需要在其中访问 Access session 作用域 bean 的内容.

public class SessionCleanup implements HttpSessionListener {

@Override
public void sessionDestroyed(HttpSessionEvent ev) {

// Get context exposed at ContextLoaderListener
WebApplicationContext ctx = WebApplicationContextUtils
.getWebApplicationContext(ev.getSession().getServletContext());

// Get the beans
Access v = (Access) ctx.getBean("access");

// prints a not-null object
System.out.println(v);

// this line raise the exception
System.out.println(v.getSerial());

}


@Override
public void sessionCreated(HttpSessionEvent ev) {/*Nothing to do*/}

}

以下异常在 v.getSerial() 中引发。

Ago 14, 2012 11:44:58 PM org.apache.catalina.session.StandardSession expire
SEVERE: Session event listener threw exception
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.access': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:342)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:33)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.getTarget(Cglib2AopProxy.java:654)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:605)
at model.Access$$EnhancerByCGLIB$$438f41a5.toString(<generated>)
at java.lang.String.valueOf(String.java:2902)
at java.io.PrintStream.println(PrintStream.java:821)
at org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:242)
at service.SessionCleanup.sessionDestroyed(SessionCleanup.java:24)
at org.apache.catalina.session.StandardSession.expire(StandardSession.java:709)
at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:576)
at org.apache.catalina.session.ManagerBase.processExpires(ManagerBase.java:712)
at org.apache.catalina.session.ManagerBase.backgroundProcess(ManagerBase.java:697)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1364)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1649)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1638)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.request.SessionScope.get(SessionScope.java:90)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:328)
... 19 more

最后,这是我的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">

<display-name>session-listener-cleanup</display-name>


<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-config.xml</param-value>
</context-param>


<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


<listener>
<listener-class>service.SessionCleanup</listener-class>
</listener>


<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>


<session-config>
<session-timeout>1</session-timeout>
</session-config>


</web-app>

正如我所说,当我在 Controller 的方法 destroy 中使 session 无效时,一切都很顺利。

更新 1:找到可能的解决方案

问题的发生是因为需要请求才能让 Spring 访问 session bean。事件虽然我们有一个关联到线程的上下文,但没有请求。

这里有一些可能的选择:

  1. 按照 alexwen 的建议实现 DisposableBean 接口(interface)。这意味着将业务逻辑移动到模型对象 [here] ;
  2. 实现 DestructionAwareBeanPostProcessor 也是 alexwen 建议的。这意味着您需要在进行任何处理之前检查被处理的 bean 是否是 Access [here] ;
  3. 直接从 session 中检索 bean。这种方法不是很好,因为您使用未记录的行为来实现结果,但确实有效 [here] ;
  4. 模拟 servlet 请求并通过 RequestContextHolder 将其属性绑定(bind)到线程。这也会导致未记录的行为,能够在未来的版本中更改 [here] ;

我没有选择最后两个,因为它们没有记录。另外,我不喜欢在一个特定的 bean 之后清除每个 bean 的想法。因为我也不想将业务逻辑混合到我的模型 bean 中,所以我最终创建了一个 @Service 来创建 bean 并且还有一个 destroy 方法。

这个方法负责处理访问bean。我在 Access 上实现了 DisposableBean 接口(interface),并将 AccessManager 服务注入(inject) Access bean 并调用服务 销毁方法。该服务如下所示:

@Service
public class AccessManager {

@Bean(name="access", destroyMethod="destroy")
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
@Autowired
public Access create(HttpServletRequest request) {
// creation logic
}


public void destroy(Access access) {
// disposal logic
}

}

最佳答案

如果你实现接口(interface),DisposableBean在您的 Access 类上,当 Session 被销毁时,Spring 将调用方法“destroy”。

或者,您可以向 Spring 注册一个 DestructionAwareBeanPostProcessor当范围被销毁时,它将有机会处理 Session 范围内的所有 bean。 Docs and instructions here .

如果您对 Spring 如何做这一切感到好奇,我鼓励您查看 Spring 注册为 HttpSessionBindingListener 的 DisposableBeanAdapter。与 session 。

关于java - 无法在 session 超时时获取 session 范围的 bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11963673/

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