《How Tomcat Works》读书笔记

2017-12-06
Tomcat 笔记

这本书看了这么久,差不多可以算是看完了。准确来讲是还剩两个章节没有读完。最后那两个章节的的确确是很不得劲,也有可能是自己开始浮躁起来了。我看的是中文翻译的,可气的是中文翻译很多错别字不说,居然有些地方根本就没有翻译到,“缺斤少两”很可气。然后又找原版对照着看,避免被“误入歧途”。

差不多“读完”后,有那么一点小收获:

  • 观察者模式
  • 责任链模式
  • 门面模式
  • 想到了再写

观察者模式

这个模式是我印象最深刻的,也是我最想学习的。尤其是看到了Tomcat源码中的那些骚操作。当然不仅仅是在Tomcat中有这种设计,
我在看Spring源码的时候也留意到了也有这种设计思想,内心不禁发出一个信号:教练我也想学。

接下来就针对Tomcat中的源码来对观察者模式进行简单的整理。Tomcat中许多组件都有生命周期,其实不止Tomcat,很多其他地方也有生命周期的概念:Spring生命周期,Servlet生命周期等等。生命周期就是观察者模式最好的体现。举个栗子,Service组件:StandardService就有生命周期:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
public final class StandardService
implements Lifecycle, Service {
/**
* The set of Connectors associated with this Service.
*/
private Connector connectors[] = new Connector[0];
/**
* The Container associated with this Service.
*/
private Container container = null;
/**
* The debugging detail level for this component.
*/
private int debug = 0;
/**
* Descriptive information about this component implementation.
*/
private static final String info =
"org.apache.catalina.core.StandardService/1.0";
/**
* Has this component been initialized?
*/
private boolean initialized = false;
/**
* The name of this service.
*/
private String name = null;
/**
* The lifecycle event support for this component.
*/
private LifecycleSupport lifecycle = new LifecycleSupport(this);
/**
* The string manager for this package.
*/
private static final StringManager sm =
StringManager.getManager(Constants.Package);
/**
* The <code>Server</code> that owns this Service, if any.
*/
private Server server = null;
/**
* Has this component been started?
*/
private boolean started = false;
/**
* The property change support for this component.
*/
protected PropertyChangeSupport support = new PropertyChangeSupport(this);
// ------------------------------------------------------ Lifecycle Methods
/**
* Add a LifecycleEvent listener to this component.
*
* @param listener The listener to add
*/
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
/**
* Get the lifecycle listeners associated with this lifecycle. If this
* Lifecycle has no listeners registered, a zero-length array is returned.
*/
public LifecycleListener[] findLifecycleListeners() {
return lifecycle.findLifecycleListeners();
}
/**
* Remove a LifecycleEvent listener from this component.
*
* @param listener The listener to remove
*/
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
/**
* Prepare for the beginning of active use of the public methods of this
* component. This method should be called before any of the public
* methods of this component are utilized. It should also send a
* LifecycleEvent of type START_EVENT to any registered listeners.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
public void start() throws LifecycleException {
// Validate and update our current component state
if (started) {
throw new LifecycleException
(sm.getString("standardService.start.started"));
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
System.out.println
(sm.getString("standardService.start.name", this.name));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
// Start our defined Container first
if (container != null) {
synchronized (container) {
if (container instanceof Lifecycle) {
((Lifecycle) container).start();
}
}
}
// Start our defined Connectors second
synchronized (connectors) {
for (int i = 0; i < connectors.length; i++) {
if (connectors[i] instanceof Lifecycle)
((Lifecycle) connectors[i]).start();
}
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
/**
* Gracefully terminate the active use of the public methods of this
* component. This method should be the last one called on a given
* instance of this component. It should also send a LifecycleEvent
* of type STOP_EVENT to any registered listeners.
*
* @exception LifecycleException if this component detects a fatal error
* that needs to be reported
*/
public void stop() throws LifecycleException {
// Validate and update our current component state
if (!started) {
throw new LifecycleException
(sm.getString("standardService.stop.notStarted"));
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
System.out.println
(sm.getString("standardService.stop.name", this.name));
started = false;
// Stop our defined Connectors first
synchronized (connectors) {
for (int i = 0; i < connectors.length; i++) {
if (connectors[i] instanceof Lifecycle)
((Lifecycle) connectors[i]).stop();
}
}
// Stop our defined Container second
if (container != null) {
synchronized (container) {
if (container instanceof Lifecycle) {
((Lifecycle) container).stop();
}
}
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}
/**
* Invoke a pre-startup initialization. This is used to allow connectors
* to bind to restricted ports under Unix operating environments.
*/
public void initialize()
throws LifecycleException {
if (initialized)
throw new LifecycleException (
sm.getString("standardService.initialize.initialized"));
initialized = true;
// Initialize our defined Connectors
synchronized (connectors) {
for (int i = 0; i < connectors.length; i++) {
connectors[i].initialize();
}
}
}
}

其中只保留了有关Lifecycle接口的方法实现。看看Lifecycle接口的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public interface Lifecycle {
// ----------------------------------------------------- Manifest Constants
/**
* The LifecycleEvent type for the "component start" event.
*/
public static final String START_EVENT = "start";
/**
* The LifecycleEvent type for the "component before start" event.
*/
public static final String BEFORE_START_EVENT = "before_start";
/**
* The LifecycleEvent type for the "component after start" event.
*/
public static final String AFTER_START_EVENT = "after_start";
/**
* The LifecycleEvent type for the "component stop" event.
*/
public static final String STOP_EVENT = "stop";
/**
* The LifecycleEvent type for the "component before stop" event.
*/
public static final String BEFORE_STOP_EVENT = "before_stop";
/**
* The LifecycleEvent type for the "component after stop" event.
*/
public static final String AFTER_STOP_EVENT = "after_stop";
// --------------------------------------------------------- Public Methods
/**
* Add a LifecycleEvent listener to this component.
*
* @param listener The listener to add
*/
public void addLifecycleListener(LifecycleListener listener);
/**
* Get the lifecycle listeners associated with this lifecycle. If this
* Lifecycle has no listeners registered, a zero-length array is returned.
*/
public LifecycleListener[] findLifecycleListeners();
/**
* Remove a LifecycleEvent listener from this component.
*
* @param listener The listener to remove
*/
public void removeLifecycleListener(LifecycleListener listener);
/**
* Prepare for the beginning of active use of the public methods of this
* component. This method should be called before any of the public
* methods of this component are utilized. It should also send a
* LifecycleEvent of type START_EVENT to any registered listeners.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
public void start() throws LifecycleException;
/**
* Gracefully terminate the active use of the public methods of this
* component. This method should be the last one called on a given
* instance of this component. It should also send a LifecycleEvent
* of type STOP_EVENT to any registered listeners.
*
* @exception LifecycleException if this component detects a fatal error
* that needs to be reported
*/
public void stop() throws LifecycleException;
}

除了定义两个动作startstop外,还定义了一系列常量。当然还有对监听器的操作:添加、查找和移除。监听器可以说是观察者模式中的订阅者,它向感兴趣的事件注册,等事件发生的时候它获得通知。这个模型在Tomcat中可以这样解释:某个监听器对start事件感兴趣,因此对某个生命周期组件注册了,当start事件发生了,这个监听器获得通知,响应的代码被执行。可能用语言不好解释清楚,看代码是最好理解的了。
单独去看看StandardService中的生命周期方法start()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* Prepare for the beginning of active use of the public methods of this
* component. This method should be called before any of the public
* methods of this component are utilized. It should also send a
* LifecycleEvent of type START_EVENT to any registered listeners.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
public void start() throws LifecycleException {
// Validate and update our current component state
if (started) {
throw new LifecycleException
(sm.getString("standardService.start.started"));
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
System.out.println
(sm.getString("standardService.start.name", this.name));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
// Start our defined Container first
// 调用子组件的生命周期方法
if (container != null) {
synchronized (container) {
if (container instanceof Lifecycle) {
((Lifecycle) container).start();
}
}
}
// Start our defined Connectors second
synchronized (connectors) {
for (int i = 0; i < connectors.length; i++) {
if (connectors[i] instanceof Lifecycle)
((Lifecycle) connectors[i]).start();
}
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}

我想这段代码中最惹人注意的地方肯定是

1
2
3
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
lifecycle.fireLifecycleEvent(START_EVENT, null);
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

我觉得其他的都可以忽略,仅仅关心这三行就够了。正如Lifecycle接口中常量描述的一样,start对应开始前,开始和开始后三个状态。因此在调用start的时候将这个三个事件顺序触发,那么谁去接收这几个事件呢?这就得问问我们之前说的监听器了。这里还有一个细节值得注意:

1
private LifecycleSupport lifecycle = new LifecycleSupport(this);

这也是生命周期方法的直接调用者。由此引出一个问题:我直接实现了Lifecycle接口不就完了,里面的方法自己实现就行了,干嘛还得引入这个东西再去调用一次?这个就体现一种设计思想:设想一下,加入每个组件都自己去实现一次,但是很多代码都是类似的,这样就造成了很多冗余代码,维护起来很要命。不信可以看看这个LifecycleSupport具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
public final class LifecycleSupport {
// ----------------------------------------------------------- Constructors
/**
* Construct a new LifecycleSupport object associated with the specified
* Lifecycle component.
*
* @param lifecycle The Lifecycle component that will be the source
* of events that we fire
*/
public LifecycleSupport(Lifecycle lifecycle) {
super();
this.lifecycle = lifecycle;
}
// ----------------------------------------------------- Instance Variables
/**
* The source component for lifecycle events that we will fire.
*/
private Lifecycle lifecycle = null;
/**
* The set of registered LifecycleListeners for event notifications.
*/
private LifecycleListener listeners[] = new LifecycleListener[0];
// --------------------------------------------------------- Public Methods
/**
* Add a lifecycle event listener to this component.
*
* @param listener The listener to add
*/
public void addLifecycleListener(LifecycleListener listener) {
synchronized (listeners) {
LifecycleListener results[] =
new LifecycleListener[listeners.length + 1];
for (int i = 0; i < listeners.length; i++)
results[i] = listeners[i];
results[listeners.length] = listener;
listeners = results;
}
}
/**
* Get the lifecycle listeners associated with this lifecycle. If this
* Lifecycle has no listeners registered, a zero-length array is returned.
*/
public LifecycleListener[] findLifecycleListeners() {
return listeners;
}
/**
* Notify all lifecycle event listeners that a particular event has
* occurred for this Container. The default implementation performs
* this notification synchronously using the calling thread.
*
* @param type Event type
* @param data Event data
*/
public void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = null;
synchronized (listeners) {
interested = (LifecycleListener[]) listeners.clone();
}
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}
/**
* Remove a lifecycle event listener from this component.
*
* @param listener The listener to remove
*/
public void removeLifecycleListener(LifecycleListener listener) {
synchronized (listeners) {
int n = -1;
for (int i = 0; i < listeners.length; i++) {
if (listeners[i] == listener) {
n = i;
break;
}
}
if (n < 0)
return;
LifecycleListener results[] =
new LifecycleListener[listeners.length - 1];
int j = 0;
for (int i = 0; i < listeners.length; i++) {
if (i != n)
results[j++] = listeners[i];
}
listeners = results;
}
}
}

也就是对Lifecycle的部分方法的实现,这些方法一般是不会变化的,因此单独抽离出来,假如以后想改动也仅仅对这个类去改,而不是针对每个生命周期组件去改。

我觉得有个地方很值得借鉴:

1
2
3
4
5
6
7
8
9
10
public void addLifecycleListener(LifecycleListener listener) {
synchronized (listeners) {
LifecycleListener results[] =
new LifecycleListener[listeners.length + 1];
for (int i = 0; i < listeners.length; i++)
results[i] = listeners[i];
results[listeners.length] = listener;
listeners = results;
}
}

假如是我去写这个接口我首先不会想到用数组去装listeners,我可能会使用一个list去存,这样进行添加的时候不会有这么复杂的操作。但是这里使用的是数组来处理,却达到了同样的效果。不得不佩服底层代码对这些细节的考虑。

继续接着那三行代码,看看具体实现:

1
2
3
4
5
6
7
8
9
10
11
public void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = null;
synchronized (listeners) {
interested = (LifecycleListener[]) listeners.clone();
}
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}

一眼往去,无非就是触发监听器感兴趣的事件,而且是挨个来。这里有一个LifecycleEvent类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public final class LifecycleEvent
extends EventObject {
// ----------------------------------------------------------- Constructors
/**
* Construct a new LifecycleEvent with the specified parameters.
*
* @param lifecycle Component on which this event occurred
* @param type Event type (required)
*/
public LifecycleEvent(Lifecycle lifecycle, String type) {
this(lifecycle, type, null);
}
/**
* Construct a new LifecycleEvent with the specified parameters.
*
* @param lifecycle Component on which this event occurred
* @param type Event type (required)
* @param data Event data (if any)
*/
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
super(lifecycle);
this.lifecycle = lifecycle;
this.type = type;
this.data = data;
}
// ----------------------------------------------------- Instance Variables
/**
* The event data associated with this event.
*/
private Object data = null;
/**
* The Lifecycle on which this event occurred.
*/
private Lifecycle lifecycle = null;
/**
* The event type this instance represents.
*/
private String type = null;
// ------------------------------------------------------------- Properties
/**
* Return the event data of this event.
*/
public Object getData() {
return (this.data);
}
/**
* Return the Lifecycle on which this event occurred.
*/
public Lifecycle getLifecycle() {
return (this.lifecycle);
}
/**
* Return the event type of this event.
*/
public String getType() {
return (this.type);
}
}

这个类继承了JDK中的EventObject,不用去管它。从构造器中可以看到有三个参数:生命周期对象,类型以及数据。有了这几个属性,这个生命周期事件对象可以放心去玩了。具体怎么去玩呢,和谁一起玩呢?这个得问问监听器了:

1
2
3
4
5
6
7
8
public interface LifecycleListener {
/**
* Acknowledge the occurrence of the specified event.
*
* @param event LifecycleEvent that has occurred
*/
public void lifecycleEvent(LifecycleEvent event);
}

fireLifecycleEvent(String type, Object data)方法中有这么个调用:

1
2
3
LifecycleListener interested[] = null;
...
interested[i].lifecycleEvent(event);

事件传给监听器了!
监听器拿到生命周期事件,由于事件中的数据全都有:当前生命周期对象、生命周期类型及携带的数据,因此监听器可以想怎么玩就怎么玩。演示一下怎么玩:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SimpleContextConfig implements LifecycleListener {
public void lifecycleEvent(LifecycleEvent event) {
if (Lifecycle.START_EVENT.equals(event.getType())) {
System.out.println("==============START_EVENT=================");
Context context = (Context) event.getLifecycle();
context.setConfigured(true);
}else if (Lifecycle.BEFORE_START_EVENT.equals(event.getType())) {
System.out.println("==============BEFORE_START_EVENT=================");
} else if(Lifecycle.BEFORE_STOP_EVENT.equals(event.getType())) {
System.out.println("==============BEFORE_STOP_EVENT==================");
}else if(Lifecycle.STOP_EVENT.equals(event.getType())) {
System.out.println("==============STOP_EVENT==================");
}
}
}

可以说是简单到无聊。
忘了一点,事件监听得注册上去,不然事件发生了没法响应:

1
2
LifecycleListener listener = new ContextConfig();
((Lifecycle) context).addLifecycleListener(listener);

多添加几个也无妨,只要你想。
Tomcat中给我印象最深刻的也就是Lifecycle观察者模式。相比去找一些设计模式的栗子去学习,我觉得阅读优秀的源码要理解地更透彻一些。除了观察者模式还有其他的设计思想也值得学习,慢慢总结,不断更新。


留言: