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) {
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
2.contextInitialized方法中新建了一個定時管理器,代碼如下:
public class TestTimerManager {
//新建一個定時器
Timer timer = new Timer();
public TestTimerManager() {
super();
//新建一個定時任務
TestTimerTask task = new TestTimerTask();
//設置定時任務
timer.schedule(task, firstTimeToStartTheTask, period);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
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();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在啟動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) {
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
那么在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();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
再回到web.xml
由於Servlet容器在初始化TestTaskListener時,獲取了Spring容器,所以必須保證,在此之前,Spring容器已經初始化完成。因為Spring容器的初始化也是由Listener(ContextLoaderListener)完成,該監聽器用Spring框架提供,可以在web應用啟動時啟動Spring容器。所以,在web.xml中,要先配置ContextLoaderListener,再配置TestTaskListener。