精盡 Dubbo 源碼分析 —— HTTP 服務器

1.概述

Dubbo 的 HTTP 服務器,在 dubbo-remoting-http 模塊中實現,使用在 http://、 rest://、hessian://、webservice://協議上。

dubbo-remoting-http 模塊,類圖如下:
在這裏插入圖片描述

2.API

2.1 HttpServer

實現 Resetable 接口,HTTP 服務器接口。方法如下:

/**
 * HTTP 服務器接口
 */
public interface HttpServer extends Resetable {

    /**
     * get http handler.
     *
     * @return http handler.
     */
    HttpHandler getHttpHandler();

    /**
     * get url.
     *
     * @return url
     */
    URL getUrl();

    /**
     * get local address.
     *
     * @return local address.
     */
    InetSocketAddress getLocalAddress();

    /**
     * close the channel.
     */
    void close();

    /**
     * Graceful close the channel.
     */
    void close(int timeout);

    /**
     * is bound.
     *
     * @return bound
     */
    boolean isBound();

    /**
     * is closed.
     *
     * @return closed
     */
    boolean isClosed();

}
2.2 AbstractHttpServer

實現 HttpServer 接口,HTTP 服務器抽象類。代碼如下:

/**
 * AbstractHttpServer
 *
 * HTTP 服務器抽象類
 */
public abstract class AbstractHttpServer implements HttpServer {

    /**
     * URL 對象
     */
    private final URL url;
    /**
     * 處理器
     */
    private final HttpHandler handler;
    /**
     * 是否關閉
     */
    private volatile boolean closed;

    public AbstractHttpServer(URL url, HttpHandler handler) {
        if (url == null) {
            throw new IllegalArgumentException("url == null");
        }
        if (handler == null) {
            throw new IllegalArgumentException("handler == null");
        }
        this.url = url;
        this.handler = handler;
    }

    @Override
    public HttpHandler getHttpHandler() {
        return handler;
    }

    @Override
    public URL getUrl() {
        return url;
    }

    @Override
    public void reset(URL url) {
    }

    @Override
    public boolean isBound() {
        return true;
    }

    @Override
    public InetSocketAddress getLocalAddress() {
        return url.toInetSocketAddress();
    }

    @Override
    public void close() {
        closed = true;
    }

    @Override
    public void close(int timeout) {
        close();
    }

    @Override
    public boolean isClosed() {
        return closed;
    }

}
2.3 HttpHandler

HTTP 處理器接口。方法如下:

/**
 * http invocation handler.
 *
 * HTTP 處理器接口
 */
public interface HttpHandler {

    /**
     * invoke.
     *
     * 處理器請求
     *
     * @param request  request. 請求
     * @param response response. 響應
     * @throws IOException 當 IO 發生異常
     * @throws ServletException 當 Servlet 發生異常
     */
    void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;

}
2.4 HttpBinder

HTTP 綁定器接口。方法如下:

/**
 * HttpBinder
 *
 * HTTP 綁定起接口
 */
@SPI("jetty")
public interface HttpBinder {

    /**
     * bind the server.
     *
     * @param url server url.
     * @return server.
     */
    @Adaptive({Constants.SERVER_KEY})
    HttpServer bind(URL url, HttpHandler handler);

}
2.5 DispatcherServlet

實現 javax.servlet.http.HttpServlet 接口,服務請求調度 Servlet。代碼如下:

/**
 * Service dispatcher Servlet.
 *
 * 服務調度 Servlet
 */
public class DispatcherServlet extends HttpServlet {

    private static final long serialVersionUID = 5766349180380479888L;

    /**
     * 處理器集合
     *
     * key:服務器端口
     */
    private static final Map<Integer, HttpHandler> handlers = new ConcurrentHashMap<Integer, HttpHandler>();
    /**
     * 單例
     */
    private static DispatcherServlet INSTANCE;

    public DispatcherServlet() {
        DispatcherServlet.INSTANCE = this;
    }

    public static DispatcherServlet getInstance() {
        return INSTANCE;
    }

    /**
     * 添加處理器
     *
     * @param port 服務器端口
     * @param processor 處理器
     */
    public static void addHttpHandler(int port, HttpHandler processor) {
        handlers.put(port, processor);
    }

    /**
     * 移除處理器
     *
     * @param port 服務器端口
     */
    public static void removeHttpHandler(int port) {
        handlers.remove(port);
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 獲得處理器
        HttpHandler handler = handlers.get(request.getLocalPort());
        // 處理器不存在,報錯
        if (handler == null) {// service not found.
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Service not found.");
        // 處理請求
        } else {
            handler.handle(request, response);
        }
    }

}
2.6 ServletManager

Servlet 管理器,負責管理 ServletContext ,目前僅有 dubbo-rpc-rest 模塊,需要使用到這個類。代碼如下:

public class ServletManager {

    /**
     * 外部服務器端口,用於 `servlet` 的服務器端口
     */
    public static final int EXTERNAL_SERVER_PORT = -1234;

    /**
     * 單例
     */
    private static final ServletManager instance = new ServletManager();
    /**
     * ServletContext 集合
     */
    private final Map<Integer, ServletContext> contextMap = new ConcurrentHashMap<Integer, ServletContext>();

    public static ServletManager getInstance() {
        return instance;
    }

    /**
     * 添加 ServletContext 對象
     *
     * @param port 服務器端口
     * @param servletContext ServletContext 對象
     */
    public void addServletContext(int port, ServletContext servletContext) {
        contextMap.put(port, servletContext);
    }

    /**
     * 移除 ServletContext 對象
     *
     * @param port 服務器端口
     */
    public void removeServletContext(int port) {
        contextMap.remove(port);
    }

    /**
     * 獲得 ServletContext 對象
     *
     * @param port 服務器端口
     * @return ServletContext 對象
     */
    public ServletContext getServletContext(int port) {
        return contextMap.get(port);
    }

}

3. Tomcat 實現

3.1 TomcatHttpServer

實現 AbstractHttpServer 抽象類,基於 Tomcat 的 HTTP 服務器實現類。

/**
 * 基於 Tomcat 的 HTTP 服務器實現類
 */
public class TomcatHttpServer extends AbstractHttpServer {

    private static final Logger logger = LoggerFactory.getLogger(TomcatHttpServer.class);

    /**
     * 內嵌的 Tomcat 對象
     */
    private final Tomcat tomcat;
    /**
     * URL 對象
     */
    private final URL url;

    public TomcatHttpServer(URL url, final HttpHandler handler) {
        super(url, handler);
        this.url = url;

        // 註冊 HttpHandler 到 DispatcherServlet 中
        DispatcherServlet.addHttpHandler(url.getPort(), handler);

        // 創建內嵌的 Tomcat 對象
        String baseDir = new File(System.getProperty("java.io.tmpdir")).getAbsolutePath();
        tomcat = new Tomcat();
        tomcat.setBaseDir(baseDir);
        tomcat.setPort(url.getPort());
        tomcat.getConnector().setProperty("maxThreads", String.valueOf(url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS))); // 最大線程數
//        tomcat.getConnector().setProperty(
//                "minSpareThreads", String.valueOf(url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS)));
        tomcat.getConnector().setProperty("maxConnections", String.valueOf(url.getParameter(Constants.ACCEPTS_KEY, -1))); // 最大連接池
        tomcat.getConnector().setProperty("URIEncoding", "UTF-8"); // 編碼爲 UTF-8
        tomcat.getConnector().setProperty("connectionTimeout", "60000"); // 連接超時,60 秒
        tomcat.getConnector().setProperty("maxKeepAliveRequests", "-1");
        tomcat.getConnector().setProtocol("org.apache.coyote.http11.Http11NioProtocol");

        // 添加 DispatcherServlet 到 Tomcat 中
        Context context = tomcat.addContext("/", baseDir);
        Tomcat.addServlet(context, "dispatcher", new DispatcherServlet());
        context.addServletMapping("/*", "dispatcher");

        // 添加 ServletContext 對象,到 ServletManager 中
        ServletManager.getInstance().addServletContext(url.getPort(), context.getServletContext());

        // 啓動 Tomcat
        try {
            tomcat.start();
        } catch (LifecycleException e) {
            throw new IllegalStateException("Failed to start tomcat server at " + url.getAddress(), e);
        }
    }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章