在Web容器啟動時,就需要為讓程序為我們做點事兒,比如需要啟動一個后臺線程開始掃描某個用戶的在線時長或者我們需要初始化數據庫連接等等.通常有兩種方式可以解決,這就是我們今天的主題.
- 使用自定義的Servlet類,通過設置LoadOnStartUp屬性值
- 使用ServletContextListener監聽器
Servlet的LoadOnStartUp屬性設置
@WebServlet(name = "LoginServlet",urlPatterns = {"/login"},loadOnStartup = -1)
public class LoginServlet extends HttpServlet {
//具體的Servlet編寫(init,destroy,post,get方法)
}
loadOnStartUp的屬性值決定了每一個Servlet的實例化時機,在<類比servlet請求處理和java多線程處理>中已經說明每一個Servlet只會實例化一次,那么Servlet什么時候進行實例化呢?
每個Servlet的運行都遵行如下的生命周期.
- 創建Servlet類的實例(何時創建?)
- Web容器執行Servlet類的init方法,對Servlet進行初始化.
- Web容器對其進行初始化之后,Servlet實例一直存在內存中,等待用戶的請求和相應.如果用戶客戶端時get請求,則調用Servlet類的doGet方法,否則執行doPost方法.
- Web容器停止運行時,則銷毀Servlet類,執行Servlet類的destroy方法.
回答剛才的問題:Web容器什么時候初始化Servlet類?
@WebServlet(name = "LoginServlet",urlPatterns = {"/login"},loadOnStartup = -1)
public class LoginServlet extends HttpServlet {
public LoginServlet(){
super();
System.out.println("構造方法:" + this.getClass().getSimpleName());
}
@Override
public void init() throws ServletException {
super.init();
System.out.println("初始化:" + this.getClass().getSimpleName());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//post 請求業務處理
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//Get請求業務處理
}
@Override
public void destroy() {
super.destroy();
System.out.println("銷毀:" + this.getClass().getSimpleName());
}
}
1.如果loadOnStartup的值為負數,則當用戶請求該Servlet時,Servlet進行初始化.當第一個用戶請求時,執行的結果如下.
1.構造方法:LoginServlet
2.init:LoginServlet
3.Post/Get業務處理
當第二個用戶請求時,執行的結果如下:
1.Post/Get業務處理
當Web容器停止時,執行的結果如下.
執行 destroy方法,銷毀:LoginServlet
2.如果loadOnStartup的值為正數或者0,則Web容器啟動時,Servlet就進行初始化.執行的結果如下.
1.構造方法:LoginServlet
2.init:LoginServlet
當用戶請求時,執行結果如下.
1.Post/Get業務處理
當Web容器停止時,執行的記過如下.
執行destroy方法,銷毀:LoginServlet
因此可以編寫一個Servlet,設置他的loadOnStartup屬性值為正數或者0,在Web容器啟動的時候,就實例化該Servlet,并且執行該Servlet的init方法.
如下代碼,在Web容器啟動之后,啟動后臺線程,則每隔一秒鐘,執行一次業務邏輯代碼.
@Override
public void init() throws ServletException {
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
//業務邏輯
}
}).start();
}
ServletContextListener監聽器編寫
編寫自定義的ServletContextListener監聽器,則必須使得自定義的監聽器實現ServletContextListener接口.而該接口的定義如下:
public interface ServletContextListener extends EventListener {
public void contextInitialized(ServletContextEvent sce);
public void contextDestroyed(ServletContextEvent sce);
}
當Web容器啟動時,則開始執行ServletContextListener監聽器的contextInitialized方法.而在Web容器停止運行時,執行監聽器的contextDestroyed方法.我們如果想在Web容器啟動后,做點事兒的話,可以將業務邏輯寫在該方法中.
@WebListener
public class ConnectionInitListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
//業務邏輯
//例如初始化數據庫連接等
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("web context 銷毀");
}
}
擴展
- Spring配置
- Spring mvc配置
Spring 配置
我們在Web項目中使用Spring框架的時候,需要在web.xml文件中,進行配置.而讓Tomcat或者其他Web容器在一開始運行的時候,就要感知到Spring框架,并且進行一系列類的初始化工作,我們自然而然就聯想到今天的主題,在Web容器啟動之后,做點事兒,在這里是Web容器配合Spring框架做事兒.
因此在我們實際的項目開發中,如果在web項目中需要使用Spring框架,首先要在web.xml文件中,配置ServletContextListener監聽器.Spring框架使用的是ContextLoaderListener監聽器,而該監聽器正是一個自定義的監聽器,它實現了ServletContextListener監聽器,負責在web項目中,結合Spring框架的初始化工作.
Spring mvc配置
Spring mvc的使用一個Servlet作為整個框架的入口.并且設置該Servlet的loadOnStartup屬性為1,使得Web容器啟動的時候,該Servlet就要進行初始化,從而使得Spring mvc相關的類和配置得到相應的初始化和實例化.正如我們今天主題的第一部分,Web容器啟動后,做點事兒,可以通過設置Servlet的loadOnStartup屬性,從而達到我們的目的.