Springboot ServletContextListener @Autowired null 解决办法

本文介绍了解决在SpringBoot框架下使用ServletContextListener进行启动前和停止前的操作时,如何有效利用autowired的类,避免由于beanfactory未加载导致的问题。通过实现ContextWebListener接口并重写contextInitialized和contextDestroyed方法,可以确保在启动和停止时正确地注入和使用依赖。实验证明,按照文中提供的方法操作后,即可顺利使用autowired的类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

是用SpringBoot框架进行开发的时候,如果使用ServletContextListener对spring启动前和停止前做一些清理工作的时时候,需要用到一些autowired的类,测试发现这些类在启动的时候,由于相应的beanfactory还没有加载,所以会出现问题。找了一段时间,发现下面的方法能够有效解决这个问题。解决办法也是参照stackflow上面的。。

@WebListener
public class ContextWebListener implements ServletContextListener {

	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		// TODO Auto-generated method stub
		LogHelper.info("web stop!");
		System.out.println("dao++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
	}

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		// TODO Auto-generated method stub
		// SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
		WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext())
				.getAutowireCapableBeanFactory().autowireBean(this);
		LogHelper.info("web start!");
		System.out.println("dao++++"+dao.count());
		LogHelper.info("web start! finish");
	}


	@Autowired
	private ApplicationMetricsDao dao;
}

按照上面的做法,就可以使用autowired了。


<think>我们正在处理一个SpringBoot项目从JDK1.8升级到17后,ConfigListener类未在启动时自动加载的问题。具体来说,就是`contextInitialized`方法没有被调用。可能的原因和解决方案:1. **Servlet版本和监听器注册方式的变化**:从Servlet3.0开始,我们可以使用注解来注册监听器,而不需要在web.xml中配置。但是,在SpringBoot中,通常我们使用Spring的机制来注册监听器,或者通过配置类。2. **检查监听器是否被注册**:在SpringBoot应用中,我们可以通过以下方式注册Servlet监听器:-在Spring配置类中通过`ServletListenerRegistrationBean`注册。-使用`@WebListener`注解,并在启动类上使用`@ServletComponentScan`来扫描。3. **JDK升级可能带来的影响**:JDK17引入了更严格的访问控制(例如,模块化系统)。如果监听器类所在的包没有正确导出,或者类加载问题,可能导致监听器不被加载。4. **检查类路径和依赖**:确保升级后相关的ServletAPI依赖仍然正确。Spring Boot2.x(对应JDK17)通常使用Servlet4.0或更高版本。步骤:第一步:确认监听器的注册方式-如果之前是在web.xml中注册的,那么在SpringBoot中,由于嵌入式容器,web.xml不再被使用。需要将监听器注册为Spring Bean。第二步:使用`ServletListenerRegistrationBean`注册```java@Beanpublic ServletListenerRegistrationBean<ConfigListener> listenerRegistrationBean(){ServletListenerRegistrationBean<ConfigListener>bean =new ServletListenerRegistrationBean<>();bean.setListener(new ConfigListener());returnbean;}```第三步:如果使用`@WebListener`,确保启动类有`@ServletComponentScan````java@SpringBootApplication@ServletComponentScanpublicclass Application{public staticvoid main(String[]args){SpringApplication.run(Application.class, args);}}```第四步:检查JDK模块系统的限制-如果项目是模块化的(有module-info.java),确保包含了必要的`requires`语句,特别是对ServletAPI的模块(如`jakarta.servlet`)和包含监听器类的模块的导出。第五步:检查依赖版本-升级到JDK17,通常需要升级SpringBoot到2.5+(建议2.7.x或3.x,但注意Spring Boot3.x需要JakartaEE9+)。确保`pom.xml`或`build.gradle`中的依赖正确。示例:SpringBoot2.7.x的依赖```xml<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.18</version></parent>```第六步:检查日志-启动应用时,查看日志是否有关于监听器注册的异常信息。如果问题仍然存在,请提供更多信息,例如监听器的实现代码和注册方式。相关问题:1.Spring Boot中如何注册Servlet监听器?2.从JDK8升级到17时,Spring Boot项目需要注意哪些问题?3.如何解决Java模块系统导致的类访问问题?</think>### 问题分析与解决方案 在 Spring Boot 项目中从 JDK 1.8 升级到 JDK 17 后,`ConfigListener` 的 `contextInitialized` 方法未自动加载,通常由以下原因导致: #### 1. **Servlet API 依赖变化**(最常见) JDK 17 + Spring Boot 2.7+ 默认使用 **Jakarta EE 9+**(原 Java EE 重命名),包路径从 `javax.servlet` 变为 `jakarta.servlet`: ```java // 错误(旧版 JDK 8 兼容) import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; // 正确(JDK 17+ 需修改) import jakarta.servlet.ServletContextEvent; import jakarta.servlet.ServletContextListener; ``` **解决方案**: - 修改 `ConfigListener` 的导入包路径为 `jakarta.servlet.*` - 更新 Maven/Gradle 依赖(Spring Boot 2.7+): ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.18</version> <!-- 或更高 --> </dependency> ``` #### 2. **监听器注册方式失效** Spring Boot 嵌入式容器需显式注册监听器: ```java @Configuration public class ListenerConfig { @Bean public ServletListenerRegistrationBean<ConfigListener> configListener() { return new ServletListenerRegistrationBean<>(new ConfigListener()); } } ``` #### 3. **模块系统 (JPMS) 限制** 若使用 `module-info.java`,需添加模块导出: ```java module your.module { requires jakarta.servlet; // 添加必要模块 exports com.yourpackage; // 导出监听器所在包 } ``` #### 4. **类加载隔离问题** 检查依赖冲突: ```bash mvn dependency:tree | grep &#39;servlet-api&#39; ``` 确保无旧版 `javax.servlet-api` 与 `jakarta.servlet-api` 共存。 --- ### 验证步骤 1. **检查启动日志**:搜索 `ConfigListener` 是否被加载 2. **断点调试**:在 `contextInitialized` 方法内添加断点 3. **单元测试**: ```java @SpringBootTest public class ListenerTest { @Test void contextLoads() { // 验证监听器是否被触发 } } ``` --- ### 相关问题 1. **如何解决 Spring Boot 升级后 Servlet 过滤器失效的问题?** > 需将 `javax.servlet.Filter` 改为 `jakarta.servlet.Filter`,并通过 `FilterRegistrationBean` 显式注册[^1]。 2. **JDK 17 模块化导致反射访问失败如何处理?** > 在 `module-info.java` 中添加 `opens` 指令开放包,或添加 JVM 参数 `--add-opens=your.module/your.package=ALL-UNNAMED`。 3. **Spring Boot 3.0 对 JDK 17 的兼容性有哪些关键变化?** > Spring Boot 3.0 强制使用 Jakarta EE 9+,移除对 Java EE 的支持,需重构所有 `javax.*` 导入[^2]。 [^1]: Spring Boot 官方迁移指南指出,从 2.x 升级到 3.x 需注意 Servlet API 包路径变更。 [^2]: Jakarta EE 9 于 2020 年正式重命名,Spring Framework 6 起仅支持 `jakarta.*` 命名空间。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值