这次我们Tomcat 的改动是 指责分离,同时引入一个Wrapper封装
我们的Processor 是负责处理处理请求的任务
我们的Connector 是负责通信的
详细代码如下
public class JxdHttpConnector implements Runnable {
int minProcessors = 3;
int maxProcessors = 10;
int curProcessors = 0;
//存放多个processor的池子
Deque<JxdHttpProcessor> processorDeque = new ArrayDeque<>();
private ServletContainer container;
//sessions map存放session
public static Map<String, HttpSession> sessions = new ConcurrentHashMap<>();
//创建新的session
public static JxdSession createSession() {
JxdSession session = new JxdSession();
session.setValid(true);
session.setCreationTime(System.currentTimeMillis());
String sessionId = generateSessionId();
session.setId(sessionId);
sessions.put(sessionId, session);
return (session);
}
/**
* 生成随机数方法
* @return
*/
protected static synchronized String generateSessionId() {
Random random = new Random();
long seed = System.currentTimeMillis();
random.setSeed(seed);
byte bytes[] = new byte[16];
random.nextBytes(bytes);
StringBuffer result = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
byte b2 = (byte) (bytes[i] & 0x0f);
if (b1 < 10)
result.append((char) ('0' + b1));
else
result.append((char) ('A' + (b1 - 10)));
if (b2 < 10)
result.append((char) ('0' + b2));
else
result.append((char) ('A' + (b2 - 10)));
}
return (result.toString());
}
@Override
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);
}
//初始化池子 最开始三个
initProcessorDeque();
while (true) {
Socket socket = null;
try {
//这是单线程 一个请求一个请求获取socket
socket = serverSocket.accept();
//得到一个新的processor,这个processor从池中获取(池中有可能新建)
JxdHttpProcessor processor = createProcessor();
if (processor == null) {
socket.close();
continue;
}
processor.assign(socket);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void start() {
Thread thread = new Thread(this);
thread.start();
}
//从池子中获取一个processor,如果池子为空且小于最大限制,则新建一个
private JxdHttpProcessor createProcessor() {
synchronized (processorDeque) {
if (processorDeque.size() > 0) {
return processorDeque.pop();
}
if (curProcessors < maxProcessors) {
return newProcessor();
} else {
return null;
}
}
}
private void initProcessorDeque() {
for (int i = 0; i < minProcessors; i++) {
JxdHttpProcessor processor = new JxdHttpProcessor(this);
processor.start();
processorDeque.push(processor);
}
curProcessors = minProcessors;
}
private JxdHttpProcessor newProcessor() {
JxdHttpProcessor jxdHttpProcessor = new JxdHttpProcessor(this);
jxdHttpProcessor.start();
processorDeque.push(jxdHttpProcessor);
curProcessors++;
return processorDeque.pop();
}
public void recycle(JxdHttpProcessor processor) {
processorDeque.push(processor);
}
public ServletContainer getContainer() {
return container;
}
public void setContainer(ServletContainer container) {
this.container = container;
}
}
public class JxdHttpProcessor implements Runnable {
boolean available = false;
Socket socket;
JxdHttpConnector connector;
private int serverPort = 0;
private boolean keepAlive = false;
private boolean http11 = true;
public JxdHttpProcessor(JxdHttpConnector connector) {
this.connector = connector;
}
private void process(Socket socket) { //服务器循环等待请求并处理
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
InputStream input = null;
OutputStream output = null;
// create Request object and parse
JxdRequest request = new JxdRequest();
try {
output = socket.getOutputStream();
keepAlive = true;
//先关掉keepAlive 目前 为了方便测试
// while (keepAlive) {
request.parse(socket);
// create Response object
JxdResponse response = new JxdResponse(output);
response.setRequest(request);
request.setResponse(response);
//handle session
if (request.getSessionId() == null || request.getSessionId().equals("")) {
request.getSession(true);
}
response.setCharacterEncoding("UTF-8");
response.addHeader(DefaultHeaders.CONTENT_TYPE_NAME, "text/html;charset=UTF-8");
response.sendHeaders();//发送响应头
//这段代码是测试用,可以获取的 请求参数 支持get 和post
Map<String, String[]> map = request.getParameterMap();
if (request.getUri().startsWith("/servlet/")) {
//加载动态资源
JxdServletProcessor jxdServletProcessor = new JxdServletProcessor(connector);
jxdServletProcessor.process(request, response);
} else {
//加载静态资源
StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor();
staticResourceProcessor.process(request, response);
}
response.finishResponse();
System.out.println("response header connection------"+response.getHeader("Connection"));
if ("close".equals(response.getHeader("Connection"))) {
keepAlive = false;
}
// }
//因为是多线程所以只能交给httpProcessor 来关闭
socket.close();
} catch (Exception ea) {
ea.printStackTrace();
}
}
@Override
public void run() {
while (true) {
// 等待socket分配过来
Socket socket = await();
if (socket == null) continue;
// 处理请求
process(socket);
// 回收processor
connector.recycle(this);
}
}
public void start() {
Thread thread = new Thread(this);
thread.start();
}
private synchronized Socket await() {
// 等待connector提供一个新的socket
while (!available) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 获得这个新的Socket
Socket socket = this.socket;
//设置标志为false
available = false;
//通知另外的线程
notifyAll();
return (socket);
}
public synchronized void assign(Socket socket) {
// 等待connector提供一个新的socket
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// 获取到这个新的Socket
this.socket = socket;
// 把标志设置回去
available = true;
//通知另外的线程
notifyAll();
}
}
同时引入一个Wapper
/**
* ServletContainer 主要用servletClsMap,servletInstanceMap 两个
* map 管理Servlet
*/
public class ServletWrapper {
private Servlet instance = null;
private String servletClass;
private ClassLoader loader;
private String name;
protected ServletContainer container = null;
public ServletWrapper(String servletClass, ServletContainer container) {
this.container = container;
this.servletClass = servletClass;
try {
loadServlet();
} catch (ServletException e) {
e.printStackTrace();
}
}
public ClassLoader getLoader() {
if (loader != null)
return loader;
return container.getLoader();
}
public Servlet getServlet(){
return this.instance;
}
public Servlet loadServlet() throws ServletException {
if (instance!=null) return instance;
Servlet servlet = null;
String actualClass = servletClass;
if (actualClass == null) {
throw new ServletException("servlet class has not been specified");
}
ClassLoader classLoader = getLoader();
Class classClass = null;
try {
if (classLoader!=null) {
classClass = classLoader.loadClass(actualClass);
}
}
catch (ClassNotFoundException e) {
throw new ServletException("Servlet class not found");
}
try {
servlet = (Servlet) classClass.newInstance();
}
catch (Throwable e) {
throw new ServletException("Failed to instantiate servlet");
}
try {
servlet.init(null);
}
catch (Throwable f) {
throw new ServletException("Failed initialize servlet.");
}
instance =servlet;
return servlet;
}
public void invoke(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
if (instance != null) {
instance.service(request, response);
}
}
}
引入一个Servlet 容器 ,里边是一个map 用来管理 Servlet 不必每次都要创建
/**
* ServletContainer 主要用servletClsMap,servletInstanceMap 两个
* map 管理Servlet
*/
public class ServletContainer {
JxdHttpConnector connector = null;
ClassLoader loader = null;
//包含servlet类和实例的map
Map<String, String> servletClsMap = new ConcurrentHashMap<>(); //servletName -
Map<String, ServletWrapper> servletInstanceMap = new ConcurrentHashMap<>();//servletN
public ServletContainer() {
try {
// create a URLClassLoader
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File(JxdHttpServer.WEB_ROOT);
String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
} catch (IOException e) {
System.out.println(e.toString());
}
}
public String getInfo() {
return null;
}
public ClassLoader getLoader() {
return this.loader;
}
public void setLoader(ClassLoader loader) {
this.loader = loader;
}
public JxdHttpConnector getConnector() {
return connector;
}
public void setConnector(JxdHttpConnector connector) {
this.connector = connector;
}
public String getName() {
return null;
}
public void setName(String name) {
}
//invoke方法用于从map中找到相关的servlet,然后调用
public void invoke(JxdRequest request, JxdResponse response) throws IOException, ServletException {
ServletWrapper servletWrapper = null;
String uri = request.getUri();
//首先根据uri最后一个/号来定位,后面的字符串认为是servlet名字
String servletName = uri.substring(uri.lastIndexOf("/") + 1);
String servletClassName = servletName;
servletWrapper = servletInstanceMap.get(servletName);
//如果容器内没有这个servlet,先要load类,创建新实例
if (servletWrapper == null) {
servletWrapper = new ServletWrapper(servletClassName, this);
this.servletClsMap.put(servletName, servletClassName);
this.servletInstanceMap.put(servletName, servletWrapper);
}
try {
HttpRequestFacade requestFacade = new HttpRequestFacade(request);
HttpResponseFacade responseFacade = new HttpResponseFacade(response);
System.out.println("Call service()");
//让servletWrapper去执行servlet
servletWrapper.invoke(requestFacade,responseFacade);
} catch (Exception e) {
System.out.println(e.toString());
} catch (Throwable e) {
System.out.println(e.toString());
}
}
}
JxdHttpServer 我们的启动类 也发发生了变化
public class JxdHttpServer {
public static final String WEB_ROOT = System.getProperty("user.dir");
public static final String FILE_ROOT = "D:\\";
public static void main(String[] args) {
JxdHttpConnector connector = new JxdHttpConnector();
ServletContainer container = new ServletContainer();
connector.setContainer(container);
container.setConnector(connector);
connector.start();
}
}