這個東西源於這種需求:一個應用丟到服務其後,無論用戶有沒有訪問項目,這個後臺線程都必須給我跑,並且這個線程還調用了Spring注入的bean,這樣天然就會想到去監聽Servlet的狀態,當Servlet初始化完畢後會調用ServletContextListener中的contextInitialized方法,因此能夠建立一個監聽器繼承ServletContextListener類來監聽Servlet的狀態,在contextInitialized方法中來啓動後臺的線程,可是如何使用Spring注入的bean呢?因此必須確保在啓動線程前Spring容器必須初始化完畢,Spring的初始化也是有Listener完成的,因此這裏特別注意的是自定的監聽器必須放在Spring的監聽器以後(很重要),不然沒法獲取bean屬性,會報空指針異常!java
package com.hhu.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import com.hhu.threads.DiagnosisThread; /** * 這個監聽器在WEB容器初始化後就馬上啓用了 * @author Weiguo Liu * @data 2017年11月30日 */ public class ContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("加載應用程序..."); // StationService stationService = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()).getBean(StationService.class); // System.out.println("stationService=" + stationService); /* * 建立診斷線程並啓動 */ DiagnosisThread dt = new DiagnosisThread(); dt.start(); System.out.println("Listener繼續執行"); } @Override public void contextDestroyed(ServletContextEvent sce) { // TODO Auto-generated method stub } }
<!-- 這裏不能少,web啓動後會按這個位置尋找Spring的配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring/spring-*.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class> com.hhu.listener.ContextListener </listener-class> </listener> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-*.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
因爲ServletContextListener並不被Spring管理,因此咱們不能使用@Autowired註解來獲取相應的bean屬性,而是利用ApplicationContext來獲取Bean,代碼以下web
package com.hhu.util; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * 使用getBean能夠獲取對應的bean,本身的的手動進行類型強轉 * 建立獲取SpringBean的工具類 * @author Weiguo Liu * */ public class SpringBeanUtil implements ApplicationContextAware { private static ApplicationContext applicationContext = null; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringBeanUtil.applicationContext = applicationContext; } public static Object getBeanByName(String beanName) { if (applicationContext == null) { return null; } return applicationContext.getBean(beanName); } public static <T> T getBean(Class<T> type) { return applicationContext.getBean(type); } }
這樣之後就能夠在後臺線程中愉快的獲取Spring bean了,這個工具類很強大,只要Spring初始化後,無論所在類是否被Spring管理,均可以使用以下的方式獲取spring
bean的類型 bean的名字 = (bean的類型)SpringBeanUtil.getBeanByName("bean的名字");
作的越多,也就發現本身不懂的越多,仍是要深刻理解其原理啊app