下面是JDK自带的HttpServer处理Http请求的源码和流程,我看网上貌似还没有介绍这个的流程,所有就画了一下,如有不足,请矫正。
1、官方API
https://docs.oracle.com/javase/7/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpExchange.html
文章图片
2、启动一个HttpServer demo:
private static final Map routeMap = new HashMap();
// 配置要创建的Context, key为请求的路径,value为请求的处理器,AgentServerHandler是实现HttpHandler接口,重写handle方法,处理自己的逻辑; static {
routeMap.put( "/agent/server" , new AgentServerHandler());
} public static void main(String[] args) throws Exception{
String port = PropertiesHelper.getProperty( "server.port" , "20200" );
HttpServer.create();
// 绑定地址,端口,请求队列; 队列设置成0则使用默认值:50
HttpServer server = HttpServer.create( new InetSocketAddress(Integer.parseInt(port)), 0 );
logger.info( "Loading route..." );
for (String keySet : routeMap.keySet()) {
// 可以创建多个Context,每个key对应一个Handler;
server.createContext(keySet, routeMap.get(keySet));
}
// 配置HtteServer请求处理的线程池,没有配置则使用默认的线程池;
server.setExecutor(YjThreadPool.build());
server.start();
logger.info( "Server have been started. Listen to port: " + port);
} |
class ContextList {
static final int MAX_CONTEXTS = 50 ;
LinkedList list = new LinkedList();
ContextList() {
}
public synchronized void add(HttpContextImpl var1) {
assert var1.getPath() != null ;
this .list.add(var1);
} } public synchronized HttpContextImpl createContext(String var1, HttpHandler var2) { 【JDK自带HttpServer处理Http请求】
if (var2 != null && var1 != null ) {
HttpContextImpl var3 = new HttpContextImpl( this .protocol, var1, var2, this );
// 将path和Handler封装在var3中,add到contexts链表中;
this .contexts.add(var3);
this .logger.config( "context created: " + var1);
return var3;
} else {
throw new NullPointerException( "null handler, or path parameter" );
} } removeContext 操作实质就是从LinkedList中取元素; |
流程图如下:
文章图片
1、创建线程,从线程池中获取空闲的线程,如果没有则创建,等线程池那一套, task.run();
2、ServerImpl的一个内部类Exchange实现了Runnable接口,在run方法里面执行部分逻辑;Exchange有一下几个重要的属性:
SocketChannel chan;
HttpConnection connection;
HttpContextImpl context;
InputStream rawin;
OutputStream rawout;
String protocol;
ExchangeImpl tx;
HttpContextImpl ctx;
boolean rejected = false ;
|
1、首先获取上下文对象,判断上下文是否为空,如果context不是空,则初始化 rawin和rawout,从connection对象的输入输出流中获取;
2、如果上下文是空的,则在SocketChannel中获取数据,初始化rawin和rawout;
3、根据获取的rawin和rawout创建一个Request对象,去判断Request对象的requestLine是否为空,如果是空的,则关闭当前链接,直接返回;
4、如果requestLine不是空,则去校验requestLine的合法性,如果requestList不合法,直接抛400异常Bad request line;
5、如果请求是合法的,然后根据请求的uri中的path,寻找是否存在context,参数是 this.protocol, var10.getPath(),如果没有找到path,则抛404异常,核心代码如下:
this .ctx = ServerImpl. this .contexts.findContext( this .protocol, var10.getPath());
if ( this .ctx == null ) {
this .reject( 404 , var3, "No context found for request" );
return ;
} |
this .connection.setContext( this .ctx);
if ( this .ctx.getHandler() == null ) {
this .reject( 500 , var3, "No handler for context" );
return ;
} |
8、之后构造Chain对象,执行doFilter方法,doFilter方法的核心就是调用响应的handler方法的逻辑,核心代码如下:
List var28 = this .ctx.getSystemFilters();
List var29 = this .ctx.getFilters();
Chain var21 = new Chain(var28, this .ctx.getHandler());
Chain var22 = new Chain(var29, new ServerImpl.Exchange.LinkHandler(var21));
//Chain类如下 @Exported public static class Chain {
private ListIterator
private HttpHandler handler;
public Chain(List
this .iter = var1.listIterator();
this .handler = var2;
}
public void doFilter(HttpExchange var1) throws IOException {
if (! this .iter.hasNext()) {
// 执行handle方法,也就是我们实现Handle接口,重写的handle方法
this .handler.handle(var1);
} else {
Filter var2 = (Filter) this .iter.next();
var2.doFilter(var1, this );
}
} } |
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)