- 浏览: 248686 次
- 性别:
- 来自: 南京
文章分类
最新评论
-
mabusyao:
漠北空城 写道请问下,你这个是JDK版本是多少呢?!忘记了,应 ...
HashMap 源码解读 -
漠北空城:
请问下,你这个是JDK版本是多少呢?!
HashMap 源码解读 -
schumee:
完美团队~
项目沉思录 - 1.1 -
winie:
整理下 搞成引擎嘛 国产需要这样的engine
简单工作流引擎 -
mabusyao:
某位同学给我提供的堪称完美的解决方案:1. 将三个int数组放 ...
CraneWork
LifecycleMBeanBase Server NaingResources PropertyChangeSupport Service
类名
StandardServer
继承关系
关联类
实现功能
管理Service及全局的resources
分析
在catalina类中管理及维护的Server实例,实际上就是StandardServer的实例。这个类继承了Server接口,并实现了其中的管理并维护Servcie及全局的resource的方法。
而StandardServer所继承的另一个抽象类则是LifecycleMBeanBase,这个类的结构相对比较复杂,主要目的就为了同时继承Lifecycle和MBeanRegistration的默认实现,这样就不需要再重复许多代码。而因为要提供两个不同的接口的默认实现,同时又不会产生重复的代码,LifecycleMBeanBase先继承LifecycleBase类(lifecyle的默认实现),同时又继承MBeanRegistration接口,并在实现了这个接口的方法。
Lifecycle
Tomcat中所有可以被“Container”包含的组件(包括Container本身),都实现了这个接口。它提供了修改组件状态的方法,并使用观察者模式使得监控组件状态变化及在生命周期的不同阶段进行操作的成为可能。
修改组件状态得方法包括:
init()
start()
stop()
destroy()
组件的状态包括:
BEFORE_INIT
AFTER_INIT
BEFORE_START
START
AFTER_START
BEFORE_STOP
STOP
AFTER_STOP
BEFORE_DESTROY
AFTER_DESTROY
PERIODIC(周期性的事件)
CONFIG_START
CONFIG_STOP
所有的这些状态发生时,都会触发相应的事件,想要监听到这些事件并执行相应的操作,就需要用以下的方法注册成为其监听者:
addLifecycleListener(LifecycleListener listener)
findLifecycelListener()
removeLifecycleLisnter(LifecycleListener listener)
同时,也可以随时调用以下方法获得当前状态:
getState()
getStateName()
LifecycleListener
想要注册监听某个类的状态变化,就需要继承接口LifecycleListener,这个接口只声明了一个方法:
lifecyleEvent(LifecycleEvent event)
你需要在具体实现中决定需要监听哪些事件,对这些事件相应的做出什么样的操作。
LifecycleEvent
用来实现某个事件的final类,它的构造函数接收3个参数:
public LifecycleEvent(Lifecycle lifecycle, String type, Object Data)
参数分别表示产生当前event的Lifecycle类,类型以及相应的数据。许多时候我们只需要设置第一个和第二个参数即可。
LifecycleBase & LifecycleSupport
LifecycleBase类提供了Lifecycle接口的默认实现,对于事件处理的具体实现是在LifecycleSupport类中,LifecycleBase的方法仅是简单的代理到LifecycleSupport的相应方法。
LifecycleSupport中的维护了一个LifecycleListener的数组,同时利用一个同步锁来确保每次只有一个线程在操作。
private LifecycleListener listeners[] = new LifecycleListener[0];//维护的LifecycleListener数组。 private final Object listenersLock = new Object();//同步锁 public void addLifecycleListener(LifecycleListener listener) { synchronized (listenersLock) {//首先同步锁,保证单线程访问 LifecycleListener results[] = new LifecycleListener[listeners.length + 1];//创建一个新的,长度加一的数组。 for (int i = 0; i < listeners.length; i++) results[i] = listeners[i]; results[listeners.length] = listener;//将新的listener加入。 listeners = results; } //我想这样实现的目的是为了尽量减少Collection的使用,提高性能。Just a guess。 }
其它的方法实现也大同小异。
LifecycleBase中还实现了其它修改状态的的方法,具体步骤如下
1. 修改状态前确定该修改是否合法。
2. 修改状态标记,发起状态变化事件。
3. 利用模板方法给子类提供一个抽象方法来实现具体的修改状态的实现。
4. 修改状态标记,发起状态变化事件。
public final synchronized void init() throws LifecycleException { if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); }//判断状态修改是否合法 setStateInternal(LifecycleState.INITIALIZING, null, false); //状态标记修改,启动事件 try { initInternal();//模板方法,将会由子类来实现。 } catch (LifecycleException e) { setStateInternal(LifecycleState.FAILED, null, false); throw e; } setStateInternal(LifecycleState.INITIALIZED, null, false); //状态标记修改,启动事件 } protected abstract void initInternal() throws LifecycleException;//模板方法
MBeanRegistration
这个接口是JDK中的JMX组件提供的一个接口,实现这个接口的MBean可以在JMX注册和反注册的之前之后提供一些相应的操作。
代码
作为container,StandardServer维护着两种资源:Service和Global Resources。因此,StandardServer中也包含了管理维护这两者的代码,这里拿addservice方法作为一个例子:
public void addService(Service service) { service.setServer(this); synchronized (services) { Service results[] = new Service[services.length + 1]; System.arraycopy(services, 0, results, 0, services.length); results[services.length] = service; services = results; if (getState().isAvailable()) { try { service.start(); } catch (LifecycleException e) { // Ignore } } // Report this property change to interested listeners support.firePropertyChange("service", null, service); } }
await方法
await方法包含了启动一个SocketServer并等待接收由其它Socket信息的过程。当接收到的request是一个SHUTDOWN时,整个循环就会结束,Tomcat也随之关闭。 同时,也可以通过调用该类的StopAwait方法,来达到同样的效果。我想这个应该是Tomcat内部的关闭机制。但尚未找到证据。此处存疑。
同时对于其它的非关闭request过来之后如何做处理的,这里好像也没有做处理,难道这里的SocketServer并非真正的HTTP Request监听者?尚未得知,需要进一步的学习和了解。
public void await() { // Negative values - don't wait on port - tomcat is embedded or we just don't like ports if( port == -2 ) { // undocumented yet - for embedding apps that are around, alive. return; } if( port==-1 ) { try { awaitThread = Thread.currentThread(); while(!stopAwait) { try { Thread.sleep( 10000 ); } catch( InterruptedException ex ) { // continue and check the flag } } } finally { awaitThread = null; } return; } // Set up a server socket to wait on try { awaitSocket = new ServerSocket(port, 1, InetAddress.getByName(address)); } catch (IOException e) { log.error("StandardServer.await: create[" + address + ":" + port + "]: ", e); return; } try { awaitThread = Thread.currentThread(); // Loop waiting for a connection and a valid command while (!stopAwait) { ServerSocket serverSocket = awaitSocket; if (serverSocket == null) { break; } // Wait for the next connection Socket socket = null; StringBuilder command = new StringBuilder(); try { InputStream stream; try { socket = serverSocket.accept(); socket.setSoTimeout(10 * 1000); // Ten seconds stream = socket.getInputStream(); } catch (AccessControlException ace) { log.warn("StandardServer.accept security exception: " + ace.getMessage(), ace); continue; } catch (IOException e) { if (stopAwait) { // Wait was aborted with socket.close() break; } log.error("StandardServer.await: accept: ", e); break; } // Read a set of characters from the socket int expected = 1024; // Cut off to avoid DoS attack while (expected < shutdown.length()) { if (random == null) random = new Random(); expected += (random.nextInt() % 1024); } while (expected > 0) { int ch = -1; try { ch = stream.read(); } catch (IOException e) { log.warn("StandardServer.await: read: ", e); ch = -1; } if (ch < 32) // Control character or EOF terminates loop break; command.append((char) ch); expected--; } } finally { // Close the socket now that we are done with it try { if (socket != null) { socket.close(); } } catch (IOException e) { // Ignore } } // Match against our command string boolean match = command.toString().equals(shutdown); if (match) { log.info(sm.getString("standardServer.shutdownViaPort")); break; } else log.warn("StandardServer.await: Invalid command '" + command.toString() + "' received"); } } finally { ServerSocket serverSocket = awaitSocket; awaitThread = null; awaitSocket = null; // Close the server socket and return if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { // Ignore } } } }
发表评论
-
初识ThreadLocal
2015-07-07 13:15 1476最近公司在进行Java开发人员的招聘活动,其中有一道面试题 ... -
Always clean the ThreadLocal variables.
2012-05-24 09:16 1183Any variable stored in ThreadLo ... -
(转)TOMCAT源码分析
2011-10-17 16:06 2072TOMCAT源码分析(启动框架 ... -
Tomcat 源码学习 之 Http11ConnectionHandler
2011-07-14 11:31 1803Class Name org.apache.c ... -
Tomcat 源码学习 之 JIoEndpoint(转)
2011-07-13 13:48 3430本来想自己写的,结果在网上找到别人写的,概括的非常详细,就直接 ... -
Tomcat 源码学习 之 Connector
2011-07-12 10:14 1470类名 org.apache.catali ... -
Tomcat 源码学习 之 StandardService
2011-07-07 15:57 1667类名 org.apache.catalina. ... -
Tomcat 源码学习 之 AprLifecycleListener
2011-06-30 16:52 3980类名 org.apache.catalina ... -
Tomcat 源码学习 之 Catalina
2011-06-12 18:06 1544类名 Catalina ... -
Tomcat 源码学习 之 Bootstrap
2011-06-08 09:57 4460类名 Bootstrap 继承关系 ... -
Tomcat整体架构图(转)
2011-06-06 10:35 1354从前辈那里转过来的: -
如何在关闭时进行清理工作
2011-05-27 15:11 1024我们常常会遇到这样的情况,当程序运行结束的时候,要将一些资源连 ... -
Tomcat 中的有状态线程池
2011-05-19 10:09 2735Tomcat中的connector负责将从客户端发出的请求封装 ... -
Tomcat中的Request & Response 设计结构
2011-05-18 10:22 5512老版Tomcat使用catalina作为其连接器和容器的架构, ...
相关推荐
为啥StandardServer没有init方法 LifecycleBase中的init与initInternal方法 为什么这么设计? 分析Tomcat请求过程 链接器(Connector)与容器(Container) 解耦 Connector设计 监听服务端口,读取来自...
来自《深入剖析Tomcat》 HTTP请求流程->初始日期一个HTTP请求: 前导工作: org.apache.catalina.startup.Bootstrap启动startup.sh/bat来启动其main(),main()调用Catalina的process() org.apache.catalina...
className:实现了org.apache.catalina.Server接口的类名,标准实现类是org.apache.catalina.core.StandardServer类。 Port:Tomcat服务器监听用于关闭Tomcat服务器的命令(必须) Shutdown:发送到端口上用于...
14.3 StandardServer 114 14.3.1 initialize方法 114 14.3.2 start方法 115 14.3.3 stop方法 115 14.3.4 await方法 116 14.4 Service接口 116 14.5 StandardService类 116 14.5.1 connector和container 117 14.5.2 ...
====================research the source about apache-tomcat-7.0.57====================/org/apache/catalina/startup/Bootstrap---2014/11/28/org/apache/catalina/startup/Catalina---2014/11/28当Bootstrap...
14.3 StandardServer 114 14.3.1 initialize方法 114 14.3.2 start方法 115 14.3.3 stop方法 115 14.3.4 await方法 116 14.4 Service接口 116 14.5 StandardService类 116 14.5.1 connector和container 117 14.5.2 ...
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710) at org.apache.catalina.startup.Catalina.start(Catalina.java:578) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method...
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710) at org.apache.catalina.startup.Catalina.start(Catalina.java:581) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native ...
小皮海在推荐行中输入一个推荐的“ python standardserver.py(数字)”。 (数字)是指服务器将在计算机上绑定到的端口号。 您最好使用大于10000的数字。否则,该端口可能已被您的计算机使用,这将导致服务器无法...