首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Servlet 3.0 新特性深度解析:非同步處理、註解配置與可插拔架構

     編輯:Java 相關知識

Servlet 3.0 作為 Java EE 6 核心規格,引入三大革命性特性:**非同步處理** 解決執行緒阻塞、**註解配置** 消除 web.xml、**可插拔架構** 實現模組化擴充。本文深度解析每項特性的原理、配置與實戰應用。

一、非同步處理:釋放執行緒,提升併發

傳統阻塞模式

請求 → Servlet 執行緒 → 業務邏輯 (阻塞) → 響應 → 執行緒釋放
問題:高併發時執行緒池耗盡,新請求排隊/拒絕

非同步模式

請求 → Servlet 執行緒 → 啟動非同步上下文 → 執行緒立即返回容器
                    ↓
            非同步執行緒 → 業務邏輯 → 直接響應或轉發
                    ↓
            complete() 結束非同步處理

啟用非同步支援

配置方式設定
web.xml<async-supported>true</async-supported> 在 <servlet>/<filter> 內
@WebServlet@WebServlet(urlPatterns="/async", asyncSupported=true)
@WebFilter@WebFilter(urlPatterns="/async", asyncSupported=true)

完整範例:模擬耗時業務

@WebServlet(urlPatterns = "/demo", asyncSupported = true)
public class AsyncDemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException, ServletException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.println("進入 Servlet 時間:" + new Date() + ".
"); out.flush(); // 1. 啟動非同步上下文 AsyncContext ctx = req.startAsync(); // 2. 交給非同步執行緒處理 new Thread(new Executor(ctx)).start(); // 3. 主執行緒立即返回 out.println("結束 Servlet 時間:" + new Date() + ".
"); out.flush(); } } class Executor implements Runnable { private AsyncContext ctx; public Executor(AsyncContext ctx) { this.ctx = ctx; } @Override public void run() { try { Thread.sleep(10000); // 模擬 10 秒耗時業務 PrintWriter out = ctx.getResponse().getWriter(); out.println("業務處理完畢時間:" + new Date() + ".
"); out.flush(); ctx.complete(); // 關鍵:通知容器非同步處理結束 } catch (Exception e) { e.printStackTrace(); } } }

AsyncListener:監聽非同步生命週期

AsyncContext ctx = req.startAsync();
ctx.addListener(new AsyncListener() {
    @Override public void onComplete(AsyncEvent event) throws IOException {
        // 清理資源、記錄日誌
    }
    @Override public void onTimeout(AsyncEvent event) throws IOException { }
    @Override public void onError(AsyncEvent event) throws IOException { }
    @Override public void onStartAsync(AsyncEvent event) throws IOException { }
});

二、註解配置:告別 web.xml

核心註解對照表

註解對應 web.xml 元素關鍵屬性
@WebServlet<servlet> + <servlet-mapping>urlPatterns、name、loadOnStartup、initParams、asyncSupported
@WebFilter<filter> + <filter-mapping>urlPatterns/servletNames、filterName、dispatcherTypes、asyncSupported
@WebListener<listener>value (描述)
@WebInitParam<init-param>name、value、description
@MultipartConfig無 (新增檔案上傳支援)location、maxFileSize、maxRequestSize、fileSizeThreshold

@WebServlet 完整範例

@WebServlet(
    urlPatterns = {"/simple"},
    asyncSupported = true,
    loadOnStartup = -1,
    name = "SimpleServlet",
    displayName = "ss",
    initParams = @WebInitParam(name = "username", value = "tom")
)
public class SimpleServlet extends HttpServlet { ... }

等效 web.xml

<servlet>
  <display-name>ss</display-name>
  <servlet-name>SimpleServlet</servlet-name>
  <servlet-class>footmark.servlet.SimpleServlet</servlet-class>
  <load-on-startup>-1</load-on-startup>
  <async-supported>true</async-supported>
  <init-param>
    <param-name>username</param-name>
    <param-value>tom</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>SimpleServlet</servlet-name>
  <url-pattern>/simple</url-pattern>
</servlet-mapping>

metadata-complete 控制掃描

<web-app metadata-complete="true">  <!-- 忽略所有註解、web-fragment.xml -->
<web-app metadata-complete="false"> <!-- 預設:啟用註解掃描與可插拔 -->

三、可插拔架構:Web 模組部署描述符片段

核心概念

  • web-fragment.xml:放在 JAR 的 META-INF/ 目錄,內容結構與 web.xml 幾乎相同
  • JAR 放入 WEB-INF/lib/,容器啟動自動掃描合併
  • 實現類似 Struts2 外掛機制:不修改主應用,僅加入 JAR 即擴充功能

web-fragment.xml 範例

<?xml version="1.0" encoding="UTF-8"?>
<web-fragment
    xmlns="https://java.sun.com/xml/ns/javaee"
    xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    version="3.0"
    xsi:schemaLocation="https://java.sun.com/xml/ns/javaee
                        https://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
    metadata-complete="true">
  <servlet>
    <servlet-name>fragment</servlet-name>
    <servlet-class>footmark.servlet.FragmentServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>fragment</servlet-name>
    <url-pattern>/fragment</url-pattern>
  </servlet-mapping>
</web-fragment>

載入順序控制:<ordering>

<web-fragment>
  <name>FragmentA</name>
  <ordering>
    <after>
      <name>FragmentB</name>
      <name>FragmentC</name>
    </after>
    <before>
      <others/>  <!-- 其他所有 fragment -->
    </before>
  </ordering>
  ...
</web-fragment>
  • <name>:標識當前 fragment,供其他 fragment 參考
  • <after>:必須在指定 fragment 之後解析
  • <before>:必須在指定 fragment 之前解析
  • <others/>:除當前外的所有 fragment,優先級低於具名規則

四、ServletContext 動態註冊 API

運行時動態新增 Servlet/Filter/Listener:

ServletRegistration.Dynamic reg = servletContext.addServlet("dynamic", "com.example.DynamicServlet");
reg.addMapping("/dynamic/*");
reg.setLoadOnStartup(1);
reg.setAsyncSupported(true);
  • 調用時機:ServletContextListener.contextInitialized() 或 ServletContainerInitializer.onStartup()
  • ServletContainerInitializer:JAR 服務 API 發現,配合 @HandlesTypes 篩選處理類別

五、HttpServletRequest 內建檔案上傳

無需第三方庫 (commons-fileupload 等):

@WebServlet(urlPatterns="/upload", asyncSupported=true)
@MultipartConfig(location="/tmp", maxFileSize=1024*1024*10)  // 10MB
public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
        Part photo = req.getPart("photo");  // 取得單一檔案
        photo.write("photo.jpg");           // 一行儲存
        // 或 req.getParts() 取得所有檔案
    }
}

注意:請求 Content-Type 必須為 multipart/form-data,否則拋異常。

六、總結與遷移建議

特性遷移優先級建議
非同步處理高長輪詢、Comet、WebSocket 前身、耗時業務必用
註解配置中新專案全註解,舊專案漸進式遷移
可插拔架構中框架開發者必備,應用層視模組化需求
檔案上傳高立即替換 commons-fileupload,簡化依賴

Servlet 3.0 為現代 Java Web 框架 (Spring MVC 3.2+、Struts 2.3+、JSF 2.2+) 奠定基礎,掌握這些特性能深入理解框架底層運作並寫出高效能應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved