手写 tomcat (nio)
下载 :demo
测试:
public class NIOSocketServerForTomcat {
private String host = "127.0.0.1";
private int port = 8080;
//private ExecutorService exec = Executors.newFixedThreadPool(60);
private ExecutorService exec = new ThreadPoolExecutor(60, 60, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(2000));
private ServerSocketChannel serverSocketChannel;
private Selector selector;
private NIOSocketServerForTomcat init(){
this.host = "127.0.0.1";
this.port = 8080;
return this;
}
private void start() {
try {
serverSocketChannel= ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(8080));
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(1000);
Set selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if(key.isAcceptable()){
SocketChannel channel = serverSocketChannel.accept();
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_READ );
} else if(key.isReadable()) {
SocketChannel channel = (SocketChannel) key.channel();
channel.configureBlocking(false);
exec.submit(new NIOServerHanddler(channel));
key.cancel();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new NIOSocketServerForTomcat().init().start() ;
}
}
public class NIOServerHanddler implements Runnable {
private SocketChannel channel;
public NIOServerHanddler(SocketChannel channel) {
this.channel = channel;
}
@Override
public void run() {
try {
ByteBuffer bb = ByteBuffer.allocate(1024);
channel.read(bb);
bb.flip();
byte[] array = bb.array();
bb.clear();
System.out.println(new String(array));
HttpServletRequest req = new HttpServletRequest(new String (array));
System.out.println(FastJsonUtils.toJSONString(req));
HttpServletResponse resp = new HttpServletResponse(channel);
Map handdlerMapping = HttpServletContext.getInstace().getHanddlerMapping();
XmlServletEntity target = null;
for (XmlServletEntity entity : handdlerMapping.values()) {
if (!"".equals(req.getUrl()) &&!"/".equals(req.getUrl()) && req.getUrl().startsWith(entity.getServletpattern())) {
target = entity;
}
}
if (null == target) {
RespEntity respEntity = new RespEntity();
respEntity.setCode(RespEnums.RESP_ERROR_NOT_FOUND.getCode());
respEntity.setMsg(RespEnums.RESP_ERROR_NOT_FOUND.getDesc());
resp.write(FastJsonUtils.toJSONString(respEntity));
}else{
try {
Class> clazz = Class.forName(target.getServletClass());
HttpServlet httpServlet =(HttpServlet) clazz.newInstance();
httpServlet.service(req, resp);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if (channel != null) {
channel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class HttpServlet {
public void service(HttpServletRequest reqest,HttpServletResponse response){
String method = reqest.getMethod();
if ("GET".equalsIgnoreCase(method)){
this.doGet(reqest, response);
} else if ("POST".equalsIgnoreCase(method)) {
this.doPost(reqest, response);
}
}
public void doGet(HttpServletRequest reqest,HttpServletResponse response){
}
public void doPost(HttpServletRequest reqest,HttpServletResponse response){
}
}
public class HttpServletRequest {
private String CHAR_ENTER = "\r\n";
private String CHAR_SPACE = " ";
private String CHAR_GET = "GET";
private String CHAR_POST = "POST";
private String CHAR_URL_SPLIT = "?";
private String CHAR_PARAMS_SPLIT = "&";
private String CHAR_PARAMS_KEY_VALUE_SPLIT = "=";
private String CHAR_HEADS_KEY_VALUE_SPLIT = ": ";
private String method;
private String url;
private String host;
private Map parameters = new HashMap();
private Map headers = new HashMap();
// GET /web/users/user?userName=baoyou&pwd=123456 HTTP/1.1
// Host: localhost:8080
// Connection: keep-alive
// Upgrade-Insecure-Requests: 1
// User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
// Accept-Encoding: gzip, deflate, sdch, br
// Accept-Language: zh-CN,zh;q=0.8
// Cookie: __guid=111872281.3385020722635865000.1513231215978.7585
// POST /web/users/user HTTP/1.1
// Host: localhost:8080
// Connection: keep-alive
// Content-Length: 26
// Cache-Control: max-age=0
// Origin: null
// Upgrade-Insecure-Requests: 1
// User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
// Content-Type: application/x-www-form-urlencoded
// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*;q=0.8
// Accept-Encoding: gzip, deflate, br
// Accept-Language: zh-CN,zh;q=0.8
// Cookie: __guid=111872281.3385020722635865000.1513231215978.7585
//
// userName=111&password=1111
public HttpServletRequest(String requestString) {
String[] arr = requestString.split(CHAR_ENTER);
String[] firstArr = arr[0].split(CHAR_SPACE);
this.method = firstArr[0];
try {
this.host = arr[1].split(CHAR_HEADS_KEY_VALUE_SPLIT)[1];
if (CHAR_GET.equals(this.method)) {
String urlAndParams = firstArr[1];
if (urlAndParams.contains(CHAR_URL_SPLIT)) {
this.url = firstArr[1].split(CHAR_URL_SPLIT)[0];
String params = firstArr[1].split(CHAR_URL_SPLIT)[1];
String[] paramsArr = params.split(CHAR_PARAMS_SPLIT);
for (String param : paramsArr) {
String[] paramsKeyValue = param.split(CHAR_PARAMS_KEY_VALUE_SPLIT);
this.parameters.put(paramsKeyValue[0], paramsKeyValue.length == 2 ?paramsKeyValue[1] : "");
}
for (int i = 1; i< arr.length && !"".equals(arr[i]) ;i++) {
String headerKeyValue = arr[i];
String[] headerKeyValues = headerKeyValue.split(CHAR_HEADS_KEY_VALUE_SPLIT);
this.parameters.put(headerKeyValues[0], headerKeyValues.length == 2 ?headerKeyValues[1] : "");
}
}else{
this.url = firstArr[1];
}
}else if(CHAR_POST.equals(this.method)){
String[] postArr = requestString.split(CHAR_ENTER+CHAR_ENTER);
if (postArr.length == 2 ) {
String[] paramsArr =postArr[1].split(CHAR_PARAMS_SPLIT);
for (String param : paramsArr) {
String[] paramsKeyValue = param.split(CHAR_PARAMS_KEY_VALUE_SPLIT);
this.parameters.put(paramsKeyValue[0], paramsKeyValue.length == 2 ?paramsKeyValue[1] : "");
}
}
for (int i = 1; i< postArr.length && !"".equals(postArr[i]) ;i++) {
String headerKeyValue = postArr[i];
String[] headerKeyValues = headerKeyValue.split(CHAR_HEADS_KEY_VALUE_SPLIT);
this.parameters.put(headerKeyValues[0], headerKeyValues.length == 2 ?headerKeyValues[1] : "");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map getParameters() {
return parameters;
}
public void setParameters(Map parameters) {
this.parameters = parameters;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Map getHeaders() {
return headers;
}
public void setHeaders(Map headers) {
this.headers = headers;
}
}
public class HttpServletResponse {
private SocketChannel channel;
private String CHAR = "UTF-8";
private static final String ENTER = "\r\n";
private static final String SPACE = " ";
public HttpServletResponse(SocketChannel channel) {
this.channel = channel;
this.CHAR = "UTF-8";
}
private String bulidHeader(String s){
StringBuilder contextText = new StringBuilder();
contextText.append(s);
StringBuilder sb = new StringBuilder();
/*通用头域begin*/
sb.append("HTTP/1.1").append(SPACE).append("200").append(SPACE).append("OK").append(ENTER);
sb.append("Server:myServer").append(SPACE).append("0.0.1v").append(ENTER);
sb.append("Date:Sat,"+SPACE).append(new Date()).append(ENTER);
sb.append("Content-Type:text/html;charset=UTF-8").append(ENTER);
sb.append("Content-Length:").append(contextText.toString().getBytes().length).append(ENTER);
/*通用头域end*/
sb.append(ENTER);//空一行
sb.append(contextText);//正文部分
System.out.println(sb.toString());
return sb.toString();
}
public void write(String s) {
try {
ByteBuffer bb2 = ByteBuffer.allocate(1024);
bb2.put((bulidHeader(s)).getBytes(CHAR));
bb2.flip();
channel.write(bb2);
bb2.clear();
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class HttpServletContext {
private static Map haddlerMapping ;
private HttpServletContext (){
haddlerMapping = new SaxXMLUtil().init().getHaddlerMapping();
}
private static HttpServletContext instance;
public static HttpServletContext getInstace(){
if (instance == null) {
synchronized (HttpServletContext.class) {
if (instance == null) {
instance = new HttpServletContext();
}
}
}
return instance;
}
public Map getHanddlerMapping(){
return haddlerMapping ;
}
}
public class SaxXMLUtil extends DefaultHandler{
//private Map map;
private List listServlet;
private List listMapping;
private String tagName;
ServletEntity entityServlet;
ServletMappingEntity entityServletMapping;
private int flag = 0;
public SaxXMLUtil init(){
SAXParser parser = null;
try {
parser = SAXParserFactory.newInstance().newSAXParser();
InputStream stream=SaxXMLUtil.class.getClassLoader().getResourceAsStream("web.xml");
//调用parse()方法
parser.parse(stream, this);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return this;
}
public Map getHaddlerMapping() {
Map map = new HashMap();
for (ServletEntity servlet : listServlet) {
XmlServletEntity entity =new XmlServletEntity();
entity.setServletName(servlet.getServletName());
entity.setServletClass(servlet.getServletClass());
String servletName = servlet.getServletName();
for (ServletMappingEntity mapping : listMapping) {
if (servletName.equals(mapping.getServletName())) {
entity.setServletpattern(mapping.getServletpattern());
map.put(entity.getServletName(), entity);
break;
}
}
}
return map;
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
listServlet = new ArrayList();
listMapping = new ArrayList();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
//super.startElement(uri, localName, qName, attributes);
if(qName.equals("servlet")){
entityServlet = new ServletEntity();
this.flag = 1;
}
if(qName.equals("servlet-mapping")){
entityServletMapping = new ServletMappingEntity();
this.flag = 2;
}
this.tagName = qName;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
//super.endElement(uri, localName, qName);
if(qName.equals("servlet")){
listServlet.add( entityServlet);
flag = 0;
}
if(qName.equals("servlet-mapping")){
listMapping.add( entityServletMapping);
flag = 0;
}
this.tagName = null;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//super.characters(ch, start, length);
if(this.tagName!=null){
if(this.flag == 1){
String data=new String(ch,start,length);
if(this.tagName.equals("servlet-name")){
this.entityServlet.setServletName(data);
}
if(this.tagName.equals("servlet-class")){
this.entityServlet.setServletClass(data);
}
}else if (this.flag == 2) {
String data=new String(ch,start,length);
if(this.tagName.equals("servlet-name")){
this.entityServletMapping.setServletName(data);
}
if(this.tagName.equals("url-pattern")){
this.entityServletMapping.setServletpattern(data);
}
}
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
public static void main(String[] args) {
SaxXMLUtil util = new SaxXMLUtil();
Map map = util.init().getHaddlerMapping();
for (XmlServletEntity entity : map.values()) {
System.out.println(entity.getServletName() +"\r\t" + entity.getServletClass() +"\r\t" + entity.getServletpattern());
}
/*
secondServlet
com.curiousby.baoyou.cn.showandshare.customized.tomcat.demo.SecondServlet
/secondServlet
firstServlet
com.curiousby.baoyou.cn.showandshare.customized.tomcat.demo.FirstServlet
/firstServlet
*/
}
}
public class FirstServlet extends HttpServlet{
@Override
public void doGet(HttpServletRequest reqest, HttpServletResponse response) {
super.doGet(reqest, response);
doPost(reqest, response);
}
@Override
public void doPost(HttpServletRequest reqest, HttpServletResponse response) {
super.doPost(reqest, response);
Map parameters = reqest.getParameters();
response.write("{\"name\":\"baoyou\"}");
}
}
public class SecondServlet extends HttpServlet{
@Override
public void doGet(HttpServletRequest reqest, HttpServletResponse response) {
super.doGet(reqest, response);
doPost(reqest, response);
}
@Override
public void doPost(HttpServletRequest reqest, HttpServletResponse response) {
super.doPost(reqest, response);
response.write("SecondServlet");
}
}
firstServlet
com.curiousby.baoyou.cn.showandshare.customized.tomcat.demo.FirstServlet
firstServlet
/firstServlet
secondServlet
com.curiousby.baoyou.cn.showandshare.customized.tomcat.demo.SecondServlet
secondServlet
/secondServlet.do
捐助开发者
在兴趣的驱动下,写一个免费
的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(支持支付宝和微信 以及扣扣群),没钱捧个人场,谢谢各位。
个人主页:http://knight-black-bob.iteye.com/
谢谢您的赞助,我会做的更好!