小董亮出你的8块腹肌吧!头像
关注

自己动手写一个tomcat之3池化processor

写在前面

源码
本文来池化processor,以提高服务处理性能。同时也会将processor改造为线程,异步执行,这样可以不用阻塞连接器connector的执行过程,进一步提高程序性能。

1:正文

首先将processor改造为线程,也很简单,只需要实现java.lang.Runnable接口即可,具体改造如下:

package monitomcat.server;

// ...

public class HttpProcessor implements Runnable {
    Socket socket;
    boolean available = false;
    // 维护连接器对象,池化使用
    HttpConnector connector;

    // ...

    @Override
    public void run() {
        while (true) {
            // Wait for the next socket to be assigned
            Socket socket = await();

            if (socket == null) continue;

            // Process the request from this socket
            process(socket);

            // Finish up this request处理完毕,归还处理器到dequeue中以备下次使用
            connector.recycle(this);

        }
    }

    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }

    public void process(Socket socket) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        InputStream input = null;
        OutputStream output = null;
        try {
            // ...

            // Close the socket业务处理完毕关闭套接字
            socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    synchronized void assign(Socket socket) {
        System.out.println("HttpProcessor.assign...");
        // wait for the connector to provide a new Socket
        while (available) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        // Store the newly available Socket and notify our thread
        this.socket = socket;
        available = true;
        notifyAll();
    }

    private synchronized Socket await() {
        System.out.println("HttpProcessor.await...");
        // Wait for the Connector to provide a new Socket
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        // Notify the Connector that we have received this Socket
        Socket socket = this.socket;
        available = false;
//        notifyAll();

        return (socket);
    }
}

run方法阻塞在await()方法上,等待socket进来。assign(Socket socket)方法用来分派socket,将会唤醒阻塞在await方法上的processor异步线程,执行业务处理,具体看下连接器connector是如何池化,以及启动processor线程,分派任务的:

package monitomcat.server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayDeque;
import java.util.Deque;

public class HttpConnector implements Runnable {
    int minProcessors = 3;
    int maxProcessors = 10;
    //    int minProcessors = 1;
//    int maxProcessors = 1;
    int curProcessors = 0;
    Deque<HttpProcessor> processors = new ArrayDeque<>();

    public void run() {
        ServerSocket serverSocket = null;
        int port = 8080;
        try {
            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }

        // initialize processors pool
        for (int i = 0; i < minProcessors; i++) {
            HttpProcessor initprocessor = new HttpProcessor(this);
            initprocessor.start();
            processors.push(initprocessor);
        }
        curProcessors = minProcessors;

        while (true) {
            Socket socket = null;
            try {
                socket = serverSocket.accept();
                HttpProcessor processor = createProcessor();
                if (processor == null) {
                    socket.close();
                    continue;
                }
                processor.assign(socket);

                // Close the socket
//                socket.close();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }

    private HttpProcessor createProcessor() {
        synchronized (processors) {
            if (processors.size() > 0) {
                // removes and returns the first element of this deque
                return ((HttpProcessor) processors.pop());
            }
            if (curProcessors < maxProcessors) {
                return (((newProcessor())));
            }
            else {
                return (null);
            }
        }
    }

    private HttpProcessor newProcessor() {
        HttpProcessor initprocessor = new HttpProcessor(this);
        initprocessor.start();
        processors.push(initprocessor);
        curProcessors++;
        return ((HttpProcessor) processors.pop());
    }

    void recycle(HttpProcessor processor) {
        processors.push(processor);
    }

}

代码比较简单,看下即可,这里说下processor线程池设置了最小值和最大值,初始化时只初始最小值,当不够用时,直接new,直到达到最大值,这和jdk的线程池方案是不同的,jdk的线程池方案时考虑到了线程创建成本高,以及很快就会有可用线程两方面,而将任务暂存到任务队列中,只有在任务队列满时才会创建新的线程,但是这种方案并不适合tomcat的场景,因为暂存到任务队列的动作会降低程序执行的效率。这里要实现的是尽快执行每一个用户请求
启动服务,所有的processor都会stand by准备处理socket:

Connected to the target VM, address: '127.0.0.1:53308', transport: 'socket'
HttpProcessor.await...
HttpProcessor.await...
HttpProcessor.await...

如果有一个请求的话就会从processor池中取出一个并分配当前请求的socket给其处理,并且处理完毕后继续进入下一个stand by:
在这里插入图片描述

2:标准化request和response

按照servlet规范,request和response要实现javax.servlet.http.HttpServletRequest接口和javax.servlet.http.HttpServletResponse,如下定义HttpRequest类和HttpResponse类:

public class HttpRequest implements HttpServletRequest {}
public class HttpResponse implements HttpServletResponse {}

没有流程上的改变,具体看代码吧!源码

3:门面模式保护request和response的私有方法

门面设计模式主要用来屏蔽内部复杂的实现细节,简化用户使用的复杂度,这其中也隐含了保护内部方法的含义,所以可以使用该设计模式来保护request和response内部,不希望对外的方法。
定义response门面类:

public class HttpResponseFacade implements HttpServletResponse {
    private HttpServletResponse response;

    public HttpResponseFacade(HttpResponse response) {
        this.response = response;
    }
    
    // ...
}

定义request门面类:

public class HttpRequestFacade implements HttpServletRequest {
    private HttpServletRequest request;

    public HttpRequestFacade(HttpRequest request) {
        this.request = request;
    }
    
    // ...
}

修改负责调用servlet的ServletProcessor类,修改用户自定义servlet的service方法调用入参为门面类:

package monitomcat.server;

// ...

public class ServletProcessor {

    public void process(HttpRequest request, HttpResponse response) {
        // ...
        Servlet servlet = null;
        try {
            servlet = (Servlet) servletClass.newInstance();
//            servlet.service(request, response);
            System.out.println("call service by ");
            servlet.service(new HttpRequestFacade(request), new HttpResponseFacade(response));
        } catch (Exception e) {
            System.out.println(e.toString());
        } catch (Throwable e) {
            System.out.println(e.toString());
        }
    }

    // ...
}

源码

对于用户来说,知道的越少,越好,系统也越安全。最小知识集。

写在后面

参考文章列表

手把手带你写一个 MiniTomcat

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/wang0907/article/details/163701017

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--