最近学习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实现。
请求过来的调用顺序
看到最后还是交给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$ 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
相关推荐
**Spring Boot 快速入门 (官方quick start)** Spring Boot 是一个由 Pivotal 团队开发的框架,旨在简化创建独立的、生产级别的基于 Spring 的应用。它通过自动配置和“起步依赖”(Starter Dependency)使得设置...
- **容器适配器**:支持JBoss、Jetty、Tomcat和Resin等服务器的集成。 #### 四、授权功能 除了认证功能外,Acegi还提供了强大的授权管理机制,包括: - **Web请求授权**:可以对HTTP请求进行细粒度的权限控制。 - ...
- **下载示例代码**: 示例代码位于 `tapestry-tutorials.tar.gz` 文件中,可以从官方链接 [http://howardlewisship.com/downloads/quick-start/](http://howardlewisship.com/downloads/quick-start/) 下载。...
quick~alogic-ketty-server`,这个链接可能是一个私有的Nexus仓库,你需要根据实际情况替换为官方或者其他来源的Jetty下载地址。下载完成后,使用`tar`命令进行解压,例如: ``` cd $HOME tar -xf alogic-ketty-...
Quick start & test To start quickly, build the project : cas-shiro-demo mvn clean install and start the two web applications with jetty : cd cas-shiro-demo-app mvn jetty:run To test, - call the ...
4.1 Web开发:Spring Boot内置了Tomcat或Jetty等Servlet容器,使得你可以直接创建一个可运行的jar包进行Web开发。 4.2 Controller与视图:通过`@RestController`和`@GetMapping`等注解,你可以轻松实现RESTful API...
- 使用命令 `quick-start.bat` 自动执行 Maven 构建并启动应用。 - 对于单个模块的构建和测试,可以进入对应的模块目录(例如:`modules`),然后执行 `mvn install` 命令。 - 如果需要初始化数据库,请在示例...
另外,文档作者还提供了一些中文翻译的文档链接,比如快速开始(Quick Start)、安装指南(Installation Guide)、插件示例(Plugin Samples)、告警(Alarm)等。 综上所述,Pinpoint是一个功能强大的APM工具,...
10.2.6. Quick-start Spring CLI Example 10.3. Upgrading from an Earlier Version of Spring Boot 11. Developing Your First Spring Boot Application 11.1. Creating the POM 11.2. Adding Classpath ...