java - 出现类似 "java.lang.UnsupportedOperationException: Section 4.4 of the Servlet 3.0 specification does not permit this method to be called"的错误

标签 java spring spring-mvc spring-data-jpa

我正在将基于 Spring XML 的配置迁移到基于 Java 的配置。下面的类实现了 HttpSessionListenerApplicationContextAware,在 XML 配置下工作得很好。但是使用 Java 配置,启动 Tomcat 服务器时出现以下错误。

错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionListener' defined in com.grc.config.WebConfig: Initialization of bean failed; nested exception is java.lang.UnsupportedOperationException: Section 4.4 of the Servlet 3.0 specification does not permit this method to be called from a ServletContextListener that was not defined in web.xml, a web-fragment.xml file nor annotated with @WebListener
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:584)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)

类别:

public class SessionListener implements HttpSessionListener,ApplicationContextAware {

    private static final Logger logger = ExtendedLoggerFactory.getLogger(Info.HTTP_LOGGER);

    @Autowired
    private JdbcHSqlRepository jdbcHSqlRepository;

    @Autowired
    private LoginEventRepository loginEventRepo;

    @SuppressWarnings("unused") 
    private ApplicationContext applicationContext;

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
        this.applicationContext = applicationContext;

        if(applicationContext instanceof WebApplicationContext) {
            ((WebApplicationContext)applicationContext).getServletContext().addListener(this); 
        } 
    }

    @Override 
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        httpSessionEvent.getSession().setMaxInactiveInterval(5*60); 
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession httpSession = httpSessionEvent.getSession();

        //mark user login event as looged out
        LoginEventVO event = (LoginEventVO)httpSession.getAttribute(Constants.LOGIN_EVENT);
        if(event != null) {
            event.setActive(false);

            loginEventRepo.saveAndFlush(event.transform());
        }

        logger.debug("Session destroyed : " + httpSession.getId());
        jdbcHSqlRepository.dropSessionTables(httpSession);
    }
}

当我尝试不实现 ApplicationContextAware 时,能够启动服务器而没有任何错误,但在执行 sessionDestroyed 方法时出现以下错误。

错误:

java.lang.NullPointerException: null
    at com.grc.riskanalysis.interceptor.SessionListener.sessionDestroyed(SessionListener.java:45)
    at org.apache.catalina.session.StandardSession.expire(StandardSession.java:801)
    at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:659)
    at org.apache.catalina.session.ManagerBase.processExpires(ManagerBase.java:573)
    at org.apache.catalina.session.ManagerBase.backgroundProcess(ManagerBase.java:558)
    at org.apache.catalina.core.StandardContext.backgroundProcess(StandardContext.java:5474)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1398)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1402)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1402)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1370)
    at java.lang.Thread.run(Thread.java:748)

Java 配置中我遗漏了什么吗?

@lucid 输入后,在 sessionDestroyed() 方法中手动注入(inject)所需的依赖项,效果很好。

@Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession httpSession = httpSessionEvent.getSession();

        //mark user login event as looged out
        LoginEventVO event = (LoginEventVO)httpSession.getAttribute(Constants.LOGIN_EVENT);
        ApplicationContext ctx = WebApplicationContextUtils.
                getWebApplicationContext(httpSession.getServletContext());
        if(event != null) {
            event.setActive(false);
            if(loginEventRepo == null) {
                this.loginEventRepo = (LoginEventRepository) 
                        ctx.getBean("loginEventRepository");
            }
            loginEventRepo.saveAndFlush(event.transform());
        }

        logger.debug("Session destroyed : " + httpSession.getId());
        if(jdbcHSqlRepository == null) {
            this.jdbcHSqlRepository = (JdbcHSqlRepository) 
                    ctx.getBean("jdbcHSqlRepository");
        }

        jdbcHSqlRepository.dropSessionTables(httpSession);
    }

最佳答案

您可以像这样在应用程序中注册HttpSessionListener

删除 ApplicationContextAware 实现和相关方法

public class SessionListener implements HttpSessionListener {
  // keep required code
}

现在,我们可以使用@WebListener注解来注册并添加@ServletComponentScan到主类中。 (如果是 Spring Boot 应用程序)

@Weblistener
public class SessionListener implements HttpSessionListener {
  // keep required code
}

在非Springboot应用中,这样配置。

public class AnnotationWebAppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext container) throws ServletException {
    // other configs

    container.addListener(SessionListener.class);

    // other configs
}
 As this is not spring managed bean, we need to manually inject dependencies. (make sure bean names are correct)

@Weblistener
public class SessionListener implements HttpSessionListener {

    private LoginEventRepository loginEventRepo;

    private JdbcHSqlRepository getJdbcHSqlRepository(HttpSessionEvent evt){
      if(loginEventRepo != null) {
         ApplicationContext ctx = WebApplicationContextUtils.
             getWebApplicationContext(evt.getServletContext());

         this.loginEventRepo = (LoginEventRepository) 
                            ctx.getBean("loginEventRepo");
      }
      return this.loginEventRepo;
    }
}

关于java - 出现类似 "java.lang.UnsupportedOperationException: Section 4.4 of the Servlet 3.0 specification does not permit this method to be called"的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59434595/

相关文章:

java - 尝试根据选择的单选按钮保存单选组的状态

java - 为非并发程序编写并发 JUnit

java - Spring MVC项目代码更改后不响应浏览器请求

java - 隐藏 @ModelAttribute 变量不出现在 URL 中? Spring MVC

java - Spring MVC Controller 中的 JSON 参数

Java Jar 控制台应用程序打开 Mac 系统菜单栏

Java SimpleDateFormat 正在解析错误的日期

java - 如何将int数组转换为字节数组

java - JASYPT 与 Spring Boot 问题加密强密码并在应用程序中使用它

java - 如何禁用 oData API 的 HTTP POST REQUEST?