StandardHost被启动过程
1. protected void startInternal() throws LifecycleException {
2.
3. fireLifecycleEvent(CONFIGURE_START_EVENT, null);
4. setState(LifecycleState.STARTING);
5.
6. globalNamingResources.start();//JNDI
7.
8. // Start our defined Services
9. synchronized (servicesLock) {
10. for (int i = 0; i < services.length; i++) {
11. services[i].start();
12. }
13. }
14. }
这段代码是StandardServer里面的,可以看到,里面启动了services,然后直接转到StandService,然后StandardService的
startInternal启动了StandardEngine代码见下图。
1. protected void startInternal() throws LifecycleException {
2.
3. if(log.isInfoEnabled())
4. log.info(sm.getString("standardService.start.name", this.name));
5. setState(LifecycleState.STARTING);
6.
7. // Start our defined Container first
8. if (engine != null) {
9. synchronized (engine) {
10. engine.start();
11. }
12. }
然后再看StandardEngine的startInternal()方法
1. protected synchronized void startInternal() throws LifecycleException {
2.
3. // Log our server identification information
4. if(log.isInfoEnabled())
5. log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());
6.
7. // Standard container startup
8. super.startInternal();
9. }
可以看到这个地方有super.startInternal(); 这个super继承了containerBase这个抽象基础类,这个抽象基础类是container接口的实现,我们可以看一下下面这段代码:
1. protected synchronized void startInternal() throws LifecycleException {
2.
3. // Start our subordinate components, if any
4. //开始下一级的组件,如果有的话
5. logger = null;
6. getLogger();
7. //如果配置了集群组件,则启动
8. Cluster cluster = getClusterInternal();
9. if (cluster instanceof Lifecycle) {
10. ((Lifecycle) cluster).start();
11. }
12. //如果配置了安全组件,则启动
13. Realm realm = getRealmInternal();
14. if (realm instanceof Lifecycle) {
15. ((Lifecycle) realm).start();
16. }
17.
18. // Start our child containers, if any
19. //catalina构造server实例时,server.xml中如果存在host的子容器context,调用addChild方法
20. Container children[] = findChildren();
21. List<Future<Void>> results = new ArrayList<>();
22. for (int i = 0; i < children.length; i++) {
23. results.add(startStopExecutor.submit(new StartChild(children[i])));
24. }
25.
26. boolean fail = false;
27. for (Future<Void> result : results) {
28. try {
29. result.get();
30. } catch (Exception e) {
31. log.error(sm.getString("containerBase.threadedStartFailed"), e);
32. fail = true;
33. }
34.
35. }
36. if (fail) {
37. throw new LifecycleException(
38. sm.getString("containerBase.threadedStartFailed"));
39. }
40.
41. // Start the Valves in our pipeline (including the basic), if any
42. //启动host所持有的Pipeline组件
43. if (pipeline instanceof Lifecycle)
44. ((Lifecycle) pipeline).start();
45.
46.
47. // Start our thread
48. //开始线程,启动后台线程
49. threadStart();
50.
51. }
- 关注这一句results.add(startStopExecutor.submit(new StartChild(children[i])));这个地方用了线程的submit方法,看下面这段代码:
private static class StartChild implements Callable<Void> {
2.
3. private Container child;
4.
5. public StartChild(Container child) {
6. this.child = child;
7. }
8.
9. @Override
10. public Void call() throws LifecycleException {
11. child.start();/*在这个地方调用的*/
12. return null;
13. }
14. }
这是StartChild类,可以看到他实现了callable接口,当线程使用submit方法时,call()方法会被调用,子容器将会调用start方法,即child.start(),在这个地方启动了StandardHost。而且result是一个数组,遍历启动子容器,就是说一个容器可以启动多个子容器,如一个StandardEngine可以有多个StandardHost。可以看到catalina的架构图很明显表明了这一点。
StandardHost源码分析(部分)
1. protected synchronized void startInternal() throws LifecycleException {
2.
3. // Set error report valve
4. //该类主要用于Tomcat发生异常时输出错误页面
5. String errorValve = getErrorReportValveClass();
6. //查看pipleLine里是否有error report valve
7. if ((errorValve != null) && (!errorValve.equals(""))) {
8. try {
9. boolean found = false;
10. Valve[] valves = getPipeline().getValves();
11. for (Valve valve : valves) {
12. if (errorValve.equals(valve.getClass().getName())) {
13. found = true;
14. break;
15. }
16. }
17. if(!found) {
18. Valve valve =
19. (Valve) Class.forName(errorValve).getConstructor().newInstance();/*如果没有找到利用反射创建对象*/
20. getPipeline().addValve(valve);/*把valve加到管道里*/
21. }
22. } catch (Throwable t) {
23. ExceptionUtils.handleThrowable(t);
24. log.error(sm.getString(
25. "standardHost.invalidErrorReportValveClass",
26. errorValve), t);
27. }
28. }
29. super.startInternal();//启动虚拟主机,转到了ContainBase
30. }
可以看到,这个启动方法里面就只是做了两件事:
1.添加了一个ErrorReportValve
2.调用containerBase.StartInternal()
关于containerBase.StartInternal()方法,前面已经添加了代码和注释,不在赘述。
此时有两种情况
1.catalina构造server实例时,server.xml中如果存在host的子容器context,调用addChild方法,此时直接调用StandardContext.Start()
2.没有子容器context,触发fireLifeCycleEvent(),转到HostConfig。
把lifecycle的状态改变了。而此时有监听器,setState是基础抽象类lifecycleBase的方法,我们看一下它的相关代码。
setState:
1. protected synchronized void setState(LifecycleState state)
2. throws LifecycleException {
3. setStateInternal(state, null, true);
4. }
在看这个setStateInternal:
1. private synchronized void setStateInternal(LifecycleState state,
2. Object data, boolean check) throws LifecycleException {
3.
4. if (log.isDebugEnabled()) {
5. log.debug(sm.getString("lifecycleBase.setState", this, state));
6. }
7.
8. if (check) {
9. // Must have been triggered by one of the abstract methods (assume
10. // code in this class is correct)
11. // null is never a valid state
12. if (state == null) {
13. invalidTransition("null");
14. // Unreachable code - here to stop eclipse complaining about
15. // a possible NPE further down the method
16. return;
17. }
18.
19. // Any method can transition to failed
20. // startInternal() permits STARTING_PREP to STARTING
21. // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
22. // STOPPING
23. if (!(state == LifecycleState.FAILED ||
24. (this.state == LifecycleState.STARTING_PREP &&
25. state == LifecycleState.STARTING) ||
26. (this.state == LifecycleState.STOPPING_PREP &&
27. state == LifecycleState.STOPPING) ||
28. (this.state == LifecycleState.FAILED &&
29. state == LifecycleState.STOPPING))) {
30. // No other transition permitted
31. invalidTransition(state.name());
32. }
33. }
34.
35. this.state = state;
36. String lifecycleEvent = state.getLifecycleEvent();
37. if (lifecycleEvent != null) {
38. fireLifecycleEvent(lifecycleEvent, data);
39. }
40. }
可以在看到在最后触发了这个生命周期事件。
1. protected void fireLifecycleEvent(String type, Object data) {
2. LifecycleEvent event = new LifecycleEvent(this, type, data);
3. for (LifecycleListener listener : lifecycleListeners) {
4. listener.lifecycleEvent(event);
5. }
6. }
在Digester创建对象时,listener为HostConfig。
接下来我们分析HostConfig的代码。
Tomcat8.5源码分析-HostConfig