设为首页 收藏本站
查看: 1570|回复: 0

[经验分享] jetty quick start

[复制链接]

尚未签到

发表于 2017-2-26 06:08:33 | 显示全部楼层 |阅读模式
最近学习solr的时候发现通过jetty快速启动,对jetty的使用方法进行总结。

jetty 依赖

 

<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.14</version>
</dependency>
 
 

jetty quick start (org.mortbay.jetty.Server)

方法一:
 

Server server = new Server(10008);
ServletHandler handler = new ServletHandler();
server.setHandler(handler);
handler.addServletWithMapping(JobAddServlet.class, "/jobadd");
handler.addServletWithMapping(JobInfoServlet.class, "/jobinfo");
handler.addServletWithMapping(JobStatusServlet.class, "/jobstatus");
handler.addServletWithMapping(ProxyServlet.class, "/*");
server.start();
server.join();
 这种方法比较简单,ServletHandler全部都封装好了。下面是另外一种更底层的方法,这样也能有更多的控制。
 
方法二:
 

Server server = new Server();
QueuedThreadPool threads = new QueuedThreadPool(3);
threads.setDaemon(true);
SocketConnector conn = new SocketConnector();
conn.setPort(8989);
conn.setMaxIdleTime(3600000);
conn.setLowResourceMaxIdleTime(600000);
server.setThreadPool(threads);
server.setConnectors(new Connector[] { conn });
server.setStopAtShutdown(true);
//Initialize the servlets
Context root = new Context(server, "/jettytest", Context.SESSIONS);
//root.addServlet(Servlet404.class, "/*");
root.addServlet(WaitServlet.class, "/*");
server.start();
Thread.currentThread().join();

 Connector除了SocketConnector更常见的是使用SelectChannelConnector
 
 

    SelectChannelConnector conn=new SelectChannelConnector();
conn.setPort(port);
conn.setLowResourcesConnections(10240);
conn.setMaxIdleTime(3600000);
conn.setLowResourceMaxIdleTime(600000);
 
 

jetty ThreadPool

jetty自己实现了ThreadPool,其实内部实现和j.u.c实现类似,预先创建好Thread,通过dispatch提交一个执行的任务。
 
 

jetty org.mortbay.jetty.Connector

HTTP Connector. Implementations of this interface provide connectors for the HTTP protocol. A connector receives requests (normally from a socket) and calls the handle method of the Handler object. These operations are performed using threads from the ThreadPool set on the connector. When a connector is registered with an instance of Server, then the server will set itself as both the ThreadPool and the Handler. Note that a connector can be used without a Server if a thread pool and handler are directly provided.
前面已经提到两种重要的Connector
1.SocketConnector
Socket Connector. This connector implements a traditional blocking IO and threading model.This Connector should only be used if NIO is not available.
 
2.SelectChannelConnector
Selecting NIO connector. This connector uses efficient NIO buffers with a non blocking threading model. Direct NIO buffers are used and threads are only allocated to connections with requests. Synchronization is used to simulate blocking for the servlet API, and any unflushed content at the end of request handling is written asynchronously.
This connector is best used when there are a many connections that have idle periods.
 

jetty 如何处理请求

从Connector开始着手,SocketConnector两个重要的方法:
 


  • SocketConnector.open() 。打开socket_serverSocket= new ServerSocket()
  • SocketConnector.accept() 。接受socket socket = _serverSocket.accept();

 

accept方法的调用顺序

 
代码如下:
 

Socket socket = _serverSocket.accept();
new SocketConnector.Connection(socket).dispatch();
 
第一步调用java自带的serverSocket.accept获取到Socket。
第二部 创建一个Connection对象来处理这个socket,这个Connection是SocketConnector的内部类。其dispatch方法实际调用threadPool的dispatch方法,Connection本质是一个任务。看看其run方法:
 

public void run(){
synchronized(_connections)
{
_connections.add(this);
}
while (isStarted() && !isClosed())
{
if (_connection.isIdle())
{
if (getServer().getThreadPool().isLowOnThreads())
{
int lrmit = getLowResourceMaxIdleTime();
if (lrmit>=0 && _sotimeout!= lrmit)
{
_sotimeout=lrmit;
_socket.setSoTimeout(_sotimeout);
}
}
}                    
_connection.handle();
}
}
内部怎么又有一个_connection对象?这个 _connection是org.mortbay.jetty.HttpConnection的一个实例,在SocketConnector.Connection对象被new时内部创建。
 
 

Jetty org.mortbay.jetty.HttpConnection

 
A HttpConnection represents the connection of a HTTP client to the server and is created by an instance of a Connector. It's prime function is to associate Request and Response instances with a EndPoint.
 
A connection is also the prime mechanism used by jetty to recycle objects without pooling. The Request,Response, HttpParser, HttpGenerator and HttpFields instances are all recycled for the duration of a connection. Where appropriate, allocated buffers are also kept associated with the connection via the parser and/or generator.
 
 
HttpConnection还负责初始化 HttpParser,HttpFields,Request,Response,HttpGenerator,构造函数代码:
 

_parser = new HttpParser(_connector,endpoint,new RequestHandler(),_connector.getHeaderBufferSize(),_connector.getRequestBufferSize());
_requestFields = new HttpFields();
_responseFields = new HttpFields();
_request = new Request(this);
_response = new Response(this);
_generator = new HttpGenerator(_connector,_endp,_connector.getHeaderBufferSize(),_connector.getResponseBufferSize());
这里的Request和Response就是jetty对Servlet API中定义的javax.servlet.HttpServletRequest实现。
 
 

请求过来的调用顺序

写道

request-->SocketConnector.accept()-->new SocketConnector.Connection()-->new HttpConnection()--->QueuedThreadPool.dispatch(this)-->PoolThread.dispatch(Runnable)--->SocketConnector.Connection.run()--->HttpConnection.handle()

看到最后还是交给HttpConnection.handle()来处理这个请求。这里已经注意到了这个处理过程是通过ThreadPoll异步执行的,后面handle阻塞也不会影响到SocketConnector.accept()别的请求。PS: http client仍然会阻塞,因为等待HTTP结果。
 
当Servlet阻塞时,socketConnector.accept()还是会响应到新的socket。
threadPool.dispatch()是异步操作,SocketConnector.accept()的线程不会被阻塞。dispatch方法中会判断是否有空闲线程(_idleList.size()),如果有空闲线程继续用空闲线程。如果没有空闲线程,尝试开启新线程,判断_threads.size()是否小于_maxThreads?如果小于maxThreads创建一个Thread,否则直接返回。
 
这样存在的问题是虽然能响应socket,但实际这些socket永远不会被执行。

yunpeng@yunpeng-duitang:/duitang/dist/sys$ ab -n 10000 -c 500 http://localhost:8989/jettytest/1
yunpeng@yunpeng-duitang:/duitang/dist/sys$ netstat -antp | grep 8989 | wc -l
984

 

一些疑问

问题:SocketConnector.accept()的线程是main线程吗?
  答案:当然不是。包括SocketConnector在内的所有Connector实现类都继承于一个AbstractConnector基类,在jetty启动的时候会调用其doStart方法。见stacktrace:

"main" prio=10 tid=0x000000004054b800 nid=0xf9e at breakpoint[0x00007f078256d000]
java.lang.Thread.State: RUNNABLE
at org.mortbay.jetty.AbstractConnector.doStart(AbstractConnector.java:279)
at org.mortbay.jetty.bio.SocketConnector.doStart(SocketConnector.java:147)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
- locked <0x00000000e18c7b60> (a java.lang.Object)
at org.mortbay.jetty.Server.doStart(Server.java:235)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
- locked <0x00000000e187f2a0> (a java.lang.Object)
at mytest.MyJettyTester.main(MyJettyTester.java:28)
  AbstractConnector.doStart()实现:

if (_threadPool==null)
_threadPool=_server.getThreadPool();
if (_threadPool!=_server.getThreadPool() && (_threadPool instanceof LifeCycle))
((LifeCycle)_threadPool).start();
// Start selector thread
synchronized(this){
_acceptorThread=new Thread[getAcceptors()];
for (int i=0;i<_acceptorThread.length;i++)
{
if (!_threadPool.dispatch(new Acceptor(i)))
{
Log.warn("insufficient maxThreads configured for {}",this);
break;
}
}
}
  AbstractConnector.Acceptor.run() 的实现,最终调用accept:

while (isRunning() && getConnection()!=null){
accept(_acceptor);
}
  可见也是通过threadPool调用的。
问题:serverSocket.setReuseAddress()的作用?
答案:google
 
 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-347143-1-1.html 上篇帖子: Jetty 的Windows服务包装器 下篇帖子: jetty源码概览
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表