- 浏览: 242736 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
小小诺:
关于eclipse插件版的使用,少了一张图!
自动化代码生成工具AutoPersistence -
小小诺:
非常地棒!很敬佩!
自动化代码生成工具AutoPersistence -
liudeh_009:
besterzhao 写道冒昧问一句,processExpir ...
Tomcat的Session过期处理策略 -
besterzhao:
冒昧问一句,processExpires() 从哪里看出来“过 ...
Tomcat的Session过期处理策略 -
feijunvip:
..大神,能教我下怎么用么。。。看了半天,把那个包加到项目中? ...
对新浪,腾讯微博常用接口的统一封装
Connector类的相关配置在Tomcat的安装目录conf下的Server.xml文件里,我这次主要解析采用NIO方式处理请求的情况.在Server.xml的配置如下:
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443" />
在tomcat启动的时候,会调用Connector类的Start()方法,根据以上配置,Connector的start方法里会调用Http11NioProtocol类的start()方法,如下:
try { protocolHandler.start(); } catch (Exception e) { String errPrefix = ""; if(this.service != null) { errPrefix += "service.getName(): \"" + this.service.getName() + "\"; "; } throw new LifecycleException (errPrefix + " " + sm.getString ("coyoteConnector.protocolHandlerStartFailed", e)); }
Http11NioProtocol类的start()方法又会调用NioEndpoint类的start()方法,如下:
try { ep.start(); } catch (Exception ex) { log.error(sm.getString("http11protocol.endpoint.starterror"), ex); throw ex; }
NioEndpoint类的start()方法如下:
public void start() throws Exception { // Initialize socket if not done before if (!initialized) { init(); } if (!running) { running = true; paused = false; // Create worker collection if (getUseExecutor()) { if ( executor == null ) { TaskQueue taskqueue = new TaskQueue(); TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-"); executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf); taskqueue.setParent( (ThreadPoolExecutor) executor, this); } } else if ( executor == null ) {//avoid two thread pools being created workers = new WorkerStack(maxThreads); } // Start poller threads轮询线程的个数,默认等译cpu的个数 pollers = new Poller[getPollerThreadCount()]; for (int i=0; i<pollers.length; i++) { pollers[i] = new Poller(); Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i); pollerThread.setPriority(threadPriority); pollerThread.setDaemon(true); pollerThread.start(); } // Start acceptor threads for (int i = 0; i < acceptorThreadCount; i++) { Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); acceptorThread.setPriority(threadPriority); acceptorThread.setDaemon(daemon); acceptorThread.start(); } } }
该方式初始化了处理接受Sockt的线程Acceptor,轮询sockt的线程Poller,真正处理socket的线程池executor 或workers.Acceptor类的run方法如下:
public void run() {
// Loop until we receive a shutdown command
while (running) {
// Loop if endpoint is paused
while (paused) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Ignore
}
}
try {
// Accept the next incoming connection from the server socket
SocketChannel socket = serverSock.accept();
// Hand this socket off to an appropriate processor
//TODO FIXME - this is currently a blocking call, meaning we will be blocking
//further accepts until there is a thread available.
if ( running && (!paused) && socket != null ) {
//processSocket(socket);
if (!setSocketOptions(socket)) {//把sockt交给poller数组
try {
socket.socket().close();
socket.close();
} catch (IOException ix) {
if (log.isDebugEnabled())
log.debug("", ix);
}
}
}
}catch (SocketTimeoutException sx) {
//normal condition
}catch ( IOException x ) {
if ( running ) log.error(sm.getString("endpoint.accept.fail"), x);
} catch (OutOfMemoryError oom) {
try {
oomParachuteData = null;
releaseCaches();
log.error("", oom);
}catch ( Throwable oomt ) {
try {
try {
System.err.println(oomParachuteMsg);
oomt.printStackTrace();
}catch (Throwable letsHopeWeDontGetHere){}
}catch (Throwable letsHopeWeDontGetHere){}
}
} catch (Throwable t) {
log.error(sm.getString("endpoint.accept.fail"), t);
}
}//while
}//run
setSocketOptions(Socket socket)如下:
/**
* Process the specified connection.
*/
protected boolean setSocketOptions(SocketChannel socket) {
// Process the connection
try {
//disable blocking, APR style, we are gonna be polling it
socket.configureBlocking(false);
Socket sock = socket.socket();
socketProperties.setProperties(sock);
NioChannel channel = nioChannels.poll();
if ( channel == null ) {
// SSL setup
if (sslContext != null) {
SSLEngine engine = createSSLEngine();
int appbufsize = engine.getSession().getApplicationBufferSize();
NioBufferHandler bufhandler = new NioBufferHandler(Math.max(appbufsize,socketProperties.getAppReadBufSize()),
Math.max(appbufsize,socketProperties.getAppWriteBufSize()),
socketProperties.getDirectBuffer());
channel = new SecureNioChannel(socket, engine, bufhandler, selectorPool);
} else {
// normal tcp setup
NioBufferHandler bufhandler = new NioBufferHandler(socketProperties.getAppReadBufSize(),
socketProperties.getAppWriteBufSize(),
socketProperties.getDirectBuffer());
channel = new NioChannel(socket, bufhandler);
}
} else {
channel.setIOChannel(socket);
if ( channel instanceof SecureNioChannel ) {
SSLEngine engine = createSSLEngine();
((SecureNioChannel)channel).reset(engine);
} else {
channel.reset();
}
}
//将socket注册到Poller的Selector上
getPoller0().register(channel);
} catch (Throwable t) {
try {
log.error("",t);
}catch ( Throwable tt){}
// Tell to close the socket
return false;
}
return true;
}
getPoller0()方法如下:
public Poller getPoller0() { int idx = Math.abs(pollerRotater.incrementAndGet()) % pollers.length; return pollers[idx]; }
Poller的register()方法如下:
public void register(final NioChannel socket) { socket.setPoller(this); KeyAttachment key = keyCache.poll(); final KeyAttachment ka = key!=null?key:new KeyAttachment(); ka.reset(this,socket,getSocketProperties().getSoTimeout()); PollerEvent r = eventCache.poll(); ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into. if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER); else r.reset(socket,ka,OP_REGISTER); addEvent(r);//将sockt注册到Poller的队列中 }
addEvent()方法如下:
public void addEvent(Runnable event) { events.offer(event); if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup(); }
Poller的run()方法如下:
public void run() { // Loop until we receive a shutdown command while (running) { try { // Loop if endpoint is paused while (paused && (!close) ) { try { Thread.sleep(100); } catch (InterruptedException e) { // Ignore } } boolean hasEvents = false; hasEvents = (hasEvents | events());//往Selector注册Socket事件 // Time to terminate? if (close) { timeout(0, false); break; } int keyCount = 0; try { if ( !close ) { if (wakeupCounter.getAndSet(-1) > 0) { //if we are here, means we have other stuff to do //do a non blocking select keyCount = selector.selectNow(); } else { keyCount = selector.select(selectorTimeout); } wakeupCounter.set(0); } if (close) { timeout(0, false); selector.close(); break; } } catch ( NullPointerException x ) { //sun bug 5076772 on windows JDK 1.5 if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x); if ( wakeupCounter == null || selector == null ) throw x; continue; } catch ( CancelledKeyException x ) { //sun bug 5076772 on windows JDK 1.5 if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x); if ( wakeupCounter == null || selector == null ) throw x; continue; } catch (Throwable x) { log.error("",x); continue; } //either we timed out or we woke up, process events first if ( keyCount == 0 ) hasEvents = (hasEvents | events()); Iterator iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null; // Walk through the collection of ready keys and dispatch // any active event. while (iterator != null && iterator.hasNext()) { SelectionKey sk = (SelectionKey) iterator.next(); KeyAttachment attachment = (KeyAttachment)sk.attachment(); // Attachment may be null if another thread has called // cancelledKey() if (attachment == null) { iterator.remove(); } else { attachment.access(); iterator.remove(); processKey(sk, attachment);//将Socket交由线程池executor 或workers处理 } }//while //process timeouts timeout(keyCount,hasEvents); if ( oomParachute > 0 && oomParachuteData == null ) checkParachute(); } catch (OutOfMemoryError oom) { try { oomParachuteData = null; releaseCaches(); log.error("", oom); }catch ( Throwable oomt ) { try { System.err.println(oomParachuteMsg); oomt.printStackTrace(); }catch (Throwable letsHopeWeDontGetHere){} } } }//while synchronized (this) { this.notifyAll(); } stopLatch.countDown(); }
后续就是处理sockt请求,返回处理结果到浏览器端
发表评论
-
长连接的几种实现方式
2012-10-14 17:22 16654在日常项目中,大多的时候我们用的是短连接,一个请 ... -
从整体解读tomcat
2012-07-29 15:43 1931一. tomcat的容器组件 ... -
Tomcat的Session过期处理策略
2012-07-11 11:18 8853tomcat容器实现类都继承了Container ... -
tomcat对jsp的解析调用过程
2012-07-04 16:19 0在tomcat里面,每个StandardConten ... -
解析Tomcat处理请求的类Connector<三>
2012-06-19 14:40 2387这次主要解析采用apr方式处理请求.apr用C实现 ... -
解析Tomcat处理请求的类Connector<二>
2012-06-18 13:59 1903这次主要解析采用IO方式处理请求.在Server.xm ...
相关推荐
【标题】:“解析Tomcat处理请求的类Connector<三>” 在Java的Web服务器领域,Tomcat无疑是最为广泛使用的轻量级应用服务器之一。它以其开源、免费、高效的特点深受开发者喜爱。在这个系列的第三部分,我们将深入...
在结构上,Tomcat的顶层类元素包括`<Server>`和`<Service>`,连接器类元素负责通信接口,而容器类元素则分为`Engine`、`Host`和`Context`,它们分别负责处理请求、特定虚拟主机请求和特定Web应用请求。所有的Tomcat...
本文将详细解析Tomcat的核心配置元素,包括`<Server>`、`<Service>`、`<Engine>`、`<Host>`和`<Context>`,帮助读者更好地理解和优化Tomcat的运行环境。 首先,`<Server>`元素是Tomcat实例的顶级容器,由`org....
4. `<Engine>`元素:`<Engine>`代表一个Servlet引擎,处理来自`<Connector>`的所有请求。`name`属性是引擎的名称,通常默认为`Catalina`。它还可以包含一个或多个`<Host>`元素,每个`<Host>`代表虚拟主机。 5. `...
<artifactId>mysql-connector-java</artifactId> </dependency> <!-- 日志 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency> <!-- 连接池 --> ...
3. **WEB SERVICE部分**:这部分由`<Service>`标签表示,定义了Tomcat的服务实例,每个服务可以包含多个`<Connector>`(监听端口)和`<Engine>`(处理HTTP请求)。`<Connector>`配置了Tomcat监听的IP地址和端口,...
`<Engine>`可以包含多个`<Host>`元素,每个`<Host>`代表一个虚拟主机,处理特定域名下的请求。 然后,`<Host>`元素由`org.apache.catalina.Host`接口定义,它定义了虚拟主机的配置。`appBase`属性指定了虚拟主机的...
- `<Service>` 元素:每个 `<Service>` 元素只能有一个 `<Engine>` 元素,处理所有 `<Connector>` 元素接收到的客户请求。 - `<Engine>` 元素:处理在同一 `<Service>` 中所有 `<Connector>` 元素接收到的客户请求...
`<Valve>`是处理请求链中的一个环节,`className`定义Valve实现类。例如,`AccessLogValve`可记录应用程序的访问信息,`directory`、`pattern`等属性控制日志的输出和格式。 总结,`server.xml`配置文件是Tomcat的...
`<Service>`元素不直接处理请求,它是一个或多个`<Connector>`和一个`<Engine>`的集合。每个`<Service>`都关联一个特定的`<Engine>`,用于处理所有传入的请求。 3. **Connector 组件** `<Connector>`组件是Tomcat...
- `<Engine>` 元素是 `<Service>` 的子元素,它代表了 Tomcat 的“引擎”,负责处理 `<Connector>` 接收到的请求。 - `<Engine>` 组件可以包含一个或多个 `<Host>` 元素,每个 `<Host>` 对应一个虚拟主机。 5. **...
`<Service>`元素用于定义服务,它将网络监听器(`<Connector>`)与请求处理器(`<Engine>`)关联起来,形成一个完整的网络服务。每个`<Service>`元素都有一个唯一的`name`属性,用于标识服务。 ### 3. <Connector> ...
每个 `<Service>` 只能包含一个 `<Engine>`,用于处理在同一 `<Service>` 中的所有 `<Connector>` 接收到的客户端请求,并将处理结果返回给 `<Connector>`。 - **支持的属性**:`<Engine>` 元素通常不会直接配置...
- `<Service>`:包含一个或多个`<Connector>`和一个`<Engine>`,处理特定服务的客户请求。 - `<Connector>`:处理服务器与客户端之间的通信。 - `<Engine>`:容器类元素,处理特定Service的所有请求,可以包含多...
每个<Service>元素包含一个<Connector>,用于监听和处理网络连接,一个<Engine>用于处理特定Service的所有客户请求,以及多个<Host>,每个<Host>代表一个虚拟主机,可以包含多个<Context>,每个<Context>对应一个Web...
<artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> <!-- 日志相关 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j....
`<Engine>`元素表示一个请求处理机,负责接收和处理来自`<Connector>`的请求。关键配置包括: - **defaultHost**:指定默认处理请求的主机名,需与某`<Host>`元素的`name`属性匹配。 ### 5. <Host> 元素:虚拟主机...
`<Engine>`元素是请求处理引擎,负责接收来自`Connector`的请求并分发给相应的`Host`。`defaultHost`属性指定了未明确指定主机名时的默认处理主机。`<Host>`元素代表虚拟主机,`name`属性定义了主机名,`appBase`...
<artifactId>mysql-connector-java</artifactId> <version>8.x.x</version> </dependency> <!-- Servlet & JSTL for view rendering --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax....
SpringMVC是Spring框架的一部分,专门用于处理Web请求,它将模型、视图和控制器分离,让代码结构更加清晰,易于维护。Mybatis则是一款优秀的持久层框架,它简化了数据库操作,通过XML或注解方式灵活配置SQL,实现了...