spring无法自动注入到servlet中 空指针异常NullPointerException

xiaoxiao2021-02-28  10

1.有时候在项目中需要定时启动某个任务,对于这个需求,基于JavaEE规范,我们可以使用Listener与TimerTask来实现,代码如下:

public class TestTaskListener implements ServletContextListener { //Context()初始化方法 @Override public void contextInitialized(ServletContextEvent sce) { //新建一个定时管理器 new TestTimerManager(); } public TestTaskListener() { super(); } @Override public void contextDestroyed(ServletContextEvent sce) { } }

2.contextInitialized方法中新建了一个定时管理器,代码如下:

public class TestTimerManager { //新建一个定时器 Timer timer = new Timer(); public TestTimerManager() { super(); //新建一个定时任务 TestTimerTask task = new TestTimerTask(); //设置定时任务 timer.schedule(task, firstTimeToStartTheTask, period); } }

3.在定时任务的Constructor中新建了一个定时任务,其代码如下:

@Configuration public class TestTimerTask extends TimerTask { //采用Spring框架的依赖注入 @Autowired private SelectDataService selectDataService; public TestTimerTask() { super(); } @Override public void run(){ try { //访问数据库 MyData myData = selectDataService.selectMyDataById(id); }catch(Exception ex) { System.out.println("定时任务出错"); ex.printStackTrace(); } } }

spring是个性能非常优秀的抽象工厂,可以生产出工程所需要的实例,这里采用Spring容器的自动注入selectDataService实例。上面代码中,selectDataService这个类是采用Spring的@Service注解的,在项目中主要通过Spring容器注入到Controller中,其作用主要用来访问数据库。

运行项目将会发现NullPointerException,也就是说SelectDataService的实例没有被注入到变量selectDataService中。那么,这是什么原因呢?首先来看看配置文件。 下面是web.xml:

<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>com.test.TestTaskListener</listener-class> </listener>

在启动web项目时,Servlet容器(比如Tomcat)会读web.xml配置文件中的两个节点和,节点用来加载appliactionContext.xml(即Spring的配置文件),节点用来创建监听器(比如TestTaskListener)实例。Listener的生命周期是由servlet容器管理的,例中的TestTaskListener是由servlet容器实例化并调用其contextInitialized方法的,但是,SelectDataService是通过@Service注解的,也就是说SelectDataService是由Spring容器管理的,在Spring容器外无法直接通过依赖注入得到Spring容器管理的bean实例的引用。为了在Spring容器外得到Spring容器管理的bean,可以使用Spring提供的工具类WebApplicationContextUtils。也就是说,可以在servlet容器管理的Listener中使用该工具类获Spring管理的bean。

看如下代码:

public class TestTaskListener implements ServletContextListener { //Context()初始化方法 @Override public void contextInitialized(ServletContextEvent sce) { //获得Spring容器 WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()); //从Spring容器中获得SelectDataServlet的实例 SelectDataService selectDataService = ctx.getBean(SelectDataService.class); //新建一个定时管理器 new TestTimerManager(); } public TestTaskListener() { super(); } @Override public void contextDestroyed(ServletContextEvent sce) { } }

那么在Listener中获得的SelectDataService实例如何在TestTimerTask中使用呢?可以通过作为参数传递过去,看如下代码:

public class TestTaskListener implements ServletContextListener { //Context()初始化方法 @Override public void contextInitialized(ServletContextEvent sce) { //获得Spring容器 WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()); //从Spring容器中获得SelectDataServlet的实例 SelectDataService selectDataService = ctx.getBean(SelectDataService.class); //新建一个定时管理器 new TestTimerManager(selectDataService); } public TestTaskListener() { super(); } @Override public void contextDestroyed(ServletContextEvent sce) { } } public class TestTimerManager { //新建一个定时器 Timer timer = new Timer(); public TestTimerManager(SelectDataService selectDataService) { super(); //新建一个定时任务 TestTimerTask task = new TestTimerTask(selectDataService); //设置定时任务 timer.schedule(task, firstTimeToStartTheTask, period); } } @Configuration public class TestTimerTask extends TimerTask { private SelectDataService selectDataService; public TestTimerTask(SelectDataService selectDataService) { super(); this.selectDataService = selectDataService; } @Override public void run(){ try { //访问数据库 MyData myData = selectDataService.selectMyDataById(id); }catch(Exception ex) { System.out.println("定时任务出错"); ex.printStackTrace(); } } }

再回到web.xml 由于Servlet容器在初始化TestTaskListener时,获取了Spring容器,所以必须保证,在此之前,Spring容器已经初始化完成。因为Spring容器的初始化也是由Listener(ContextLoaderListener)完成,该监听器用Spring框架提供,可以在web应用启动时启动Spring容器。所以,在web.xml中,要先配置ContextLoaderListener,再配置TestTaskListener。

1.有时候在项目中需要定时启动某个任务,对于这个需求,基于JavaEE规范,我们可以使用Listener与TimerTask来实现,代码如下:

public class TestTaskListener implements ServletContextListener { //Context()初始化方法 @Override public void contextInitialized(ServletContextEvent sce) { //新建一个定时管理器 new TestTimerManager(); } public TestTaskListener() { super(); } @Override public void contextDestroyed(ServletContextEvent sce) { } }

2.contextInitialized方法中新建了一个定时管理器,代码如下:

public class TestTimerManager { //新建一个定时器 Timer timer = new Timer(); public TestTimerManager() { super(); //新建一个定时任务 TestTimerTask task = new TestTimerTask(); //设置定时任务 timer.schedule(task, firstTimeToStartTheTask, period); } }

3.在定时任务的Constructor中新建了一个定时任务,其代码如下:

@Configuration public class TestTimerTask extends TimerTask { //采用Spring框架的依赖注入 @Autowired private SelectDataService selectDataService; public TestTimerTask() { super(); } @Override public void run(){ try { //访问数据库 MyData myData = selectDataService.selectMyDataById(id); }catch(Exception ex) { System.out.println("定时任务出错"); ex.printStackTrace(); } } }

spring是个性能非常优秀的抽象工厂,可以生产出工程所需要的实例,这里采用Spring容器的自动注入selectDataService实例。上面代码中,selectDataService这个类是采用Spring的@Service注解的,在项目中主要通过Spring容器注入到Controller中,其作用主要用来访问数据库。

运行项目将会发现NullPointerException,也就是说SelectDataService的实例没有被注入到变量selectDataService中。那么,这是什么原因呢?首先来看看配置文件。 下面是web.xml:

<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>com.test.TestTaskListener</listener-class> </listener>

在启动web项目时,Servlet容器(比如Tomcat)会读web.xml配置文件中的两个节点和,节点用来加载appliactionContext.xml(即Spring的配置文件),节点用来创建监听器(比如TestTaskListener)实例。Listener的生命周期是由servlet容器管理的,例中的TestTaskListener是由servlet容器实例化并调用其contextInitialized方法的,但是,SelectDataService是通过@Service注解的,也就是说SelectDataService是由Spring容器管理的,在Spring容器外无法直接通过依赖注入得到Spring容器管理的bean实例的引用。为了在Spring容器外得到Spring容器管理的bean,可以使用Spring提供的工具类WebApplicationContextUtils。也就是说,可以在servlet容器管理的Listener中使用该工具类获Spring管理的bean。

看如下代码:

public class TestTaskListener implements ServletContextListener { //Context()初始化方法 @Override public void contextInitialized(ServletContextEvent sce) { //获得Spring容器 WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()); //从Spring容器中获得SelectDataServlet的实例 SelectDataService selectDataService = ctx.getBean(SelectDataService.class); //新建一个定时管理器 new TestTimerManager(); } public TestTaskListener() { super(); } @Override public void contextDestroyed(ServletContextEvent sce) { } }

那么在Listener中获得的SelectDataService实例如何在TestTimerTask中使用呢?可以通过作为参数传递过去,看如下代码:

public class TestTaskListener implements ServletContextListener { //Context()初始化方法 @Override public void contextInitialized(ServletContextEvent sce) { //获得Spring容器 WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()); //从Spring容器中获得SelectDataServlet的实例 SelectDataService selectDataService = ctx.getBean(SelectDataService.class); //新建一个定时管理器 new TestTimerManager(selectDataService); } public TestTaskListener() { super(); } @Override public void contextDestroyed(ServletContextEvent sce) { } } public class TestTimerManager { //新建一个定时器 Timer timer = new Timer(); public TestTimerManager(SelectDataService selectDataService) { super(); //新建一个定时任务 TestTimerTask task = new TestTimerTask(selectDataService); //设置定时任务 timer.schedule(task, firstTimeToStartTheTask, period); } } @Configuration public class TestTimerTask extends TimerTask { private SelectDataService selectDataService; public TestTimerTask(SelectDataService selectDataService) { super(); this.selectDataService = selectDataService; } @Override public void run(){ try { //访问数据库 MyData myData = selectDataService.selectMyDataById(id); }catch(Exception ex) { System.out.println("定时任务出错"); ex.printStackTrace(); } } }

再回到web.xml 由于Servlet容器在初始化TestTaskListener时,获取了Spring容器,所以必须保证,在此之前,Spring容器已经初始化完成。因为Spring容器的初始化也是由Listener(ContextLoaderListener)完成,该监听器用Spring框架提供,可以在web应用启动时启动Spring容器。所以,在web.xml中,要先配置ContextLoaderListener,再配置TestTaskListener。

转载请注明原文地址: https://www.6miu.com/read-2600129.html

最新回复(0)