本篇將介紹如下幾點java
Servlet是基於Java技術的web組件,容器託管的,用於生成動態內容。像其餘基於Java的組件技術同樣, Servlet也是基於平臺無關的Java類格式,被編譯爲平臺無關的字節碼,能夠被基於Java技術的webserver 動態加載並運行。容器(平時咱們所使用的tomcat就是其中一種servlet容器),有時候也叫作servlet引擎,是webserver爲支持servlet功能擴展的部分。客戶端 經過Servlet容器實現的請求/應答模型與Servlet交互。(引用自oracle官方servlet3.1規範文檔)web
servlet按照一個嚴格定義的生命週期被管理,該生命週期包括:如何被加載?實例化?初始化?處理客戶端請求?什麼時候結束服務? 該生命週期能夠經過Servlet接口中的API來表示:init、service、destroyspring
servlet容器負責加載和實例化servlet,加載和實例化能夠發生在容器啓動時,或者延遲初始化直到容器有請求須要處理時。(經過開發者配置來肯定)編程
servlet容器必須在處理客戶端請求以前,對servlet實例進行初始化(即調用Servlet.init接口)。能夠完成一些讀取持久化配置數據、初始化資源等一次性的動做。tomcat
完成初始化以後,servlet容器可使用該servlet來處理客戶端請求。(容器經過開發者的配置,即servlet-mapping來尋找適合當前請求的servlet)客戶端請求由ServletRequest類型來封裝表示、Servlet響應由ServletResponse類型來封裝表示。這兩個類型的對象都由容器進行實例化,在調用Servlet處理客戶端請求時傳遞給Servlet的service方法。在Http請求的場景下,容器提供的實現對應爲HttpServletRequest、HttpServletResponse。一個servlet實例應對多個客戶端請求的狀況,致使了咱們須要在處理請求時保證線程安全。安全
在servlet技術中,除了Servlet接口用於處理請求這個組件接口外,還存在Filter、Listener這兩個重要的組件接口。 其中Filter是一種代碼重用的技術,運行運行過程當中改變進入資源的請求和資源返回的響應中的有效負載和header信息。便可以在分發請求給servlet處理以前對請求進行攔截,以後再servlet完成處理,返回響應後對響應進行攔截。能夠用於日誌記錄、驗證等需求。 和servlet生命週期同樣,應用一樣存在生命週期。監聽應用生命週期事件可讓開發人員更好的控制ServletContext、HTTPSession和ServletRequest的生命週期,能夠更好的進行代碼分解。Servlet事件監聽器支持在ServletContext、HTTPSession和ServletRequest狀態改變時進行事件通知。oracle
實現本身的Filter能夠經過實現接口javax.servlet.Filter來完成,以後經過web.xml或者註解配置到Servlet容器中,讓容器在處理請求時應用此時配置的Filterapp
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println(getClass().getName() + " init()");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println(getClass().getName() + " doFilter()");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
複製代碼
Listener的種類能夠分爲:框架
在收到客戶端請求時,web容器肯定轉發到哪一個web應用(獲取servlet上下文路徑),以後用於映射到servlet的路徑是請求對象的請求URL減去上下文和路徑參數部分,以後應用如下步驟來找出servlet來處理請求,短路原則,一旦找到匹配的servlet,以後的步驟直接跳過異步
經過@WebListener註解配置ServletContextListener實現類,在容器初始化servlet上下文時,調用ServletContext的API來註冊
@WebListener
public class FirstServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
ServletRegistration.Dynamic dynamic = servletContext.addServlet("firstServlet", FirstServlet.class);
dynamic.addMapping("/first", "/first/*");
dynamic.setLoadOnStartup(1);
ServletRegistration.Dynamic dynamic2 = servletContext.addServlet("secondServlet", SecondServlet.class);
dynamic2.addMapping("/second", "/second/*");
dynamic2.setLoadOnStartup(1);
// 異步servlet
ServletRegistration.Dynamic firstAsyncServlet = servletContext.addServlet("firstAsyncServlet", FirstAsyncServlet.class);
firstAsyncServlet.setLoadOnStartup(1);
firstAsyncServlet.setAsyncSupported(true);
firstAsyncServlet.addMapping("/async/first", "/async/first/*");
// TODO Filter調用順序???
FilterRegistration.Dynamic filterRegistration = servletContext.addFilter("secondFilter", SecondFilter.class);
filterRegistration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD),
true, "/first");
FilterRegistration.Dynamic filterDynamic = servletContext.addFilter("firstFilter", FirstFilter.class);
filterDynamic.addMappingForUrlPatterns(
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), false, "/first");
// 非阻塞IO servlet
ServletRegistration.Dynamic firstNoBIOServlet = servletContext.addServlet("firstNoBIOServlet", FirstNoBlockIOServlet.class);
firstNoBIOServlet.setLoadOnStartup(1);
firstNoBIOServlet.setAsyncSupported(true);
firstNoBIOServlet.addMapping("/nobio/first", "/nobio/first/*");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
複製代碼
在spring中利用基於SPI機制的ServletContainerInitializer來初始化容器,具體實現方式是:
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// 指定ROOT ApplicationContext的配置類
return new Class[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
// 指定Web ApplicationContext的配置類
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
// 指定DispatcherServlet的servlet-mapping,此處指定爲default servlet。任何未找到映射的請求都會由DispatcherServlet來處理請求
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
// 配置Filter
return super.getServletFilters();
}
}
複製代碼
這篇文章中梳理了Servlet中的經常使用技術,主要涉及Servlet、Filter、Listener的知識點和配置細節。以後引伸出springMVC是如何利用這些知識點來構建一個web框架的。servlet做爲java web開發中的基石是每一個開發者都必須掌握的技能。關於springMVC中的更多原理細節將在後續文章整理髮出,期待你的關注