写在前面
源码 。
本文来池化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());
}
}
// ...
}
源码 。
对于用户来说,知道的越少,越好,系统也越安全。最小知识集。
写在后面
参考文章列表
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/wang0907/article/details/163701017



