Tomcat架构分析—— Engine

小鱼儿 2023-10-08 17:24 159阅读 0赞

文章目录

  • 一、Tomcat的核心模块(核心组件)
  • 二、Engine 组件
    • 1.核心类与依赖图
    • 2.核心类源码分析
      • 构造函数:
      • 初始化方法 init:
      • 启动方法 start:
  • 总结

一、Tomcat的核心模块(核心组件)

Tomcat主要是由这几个模块组成的:

  • Server:
    Server 是最外层的组件,他在Java虚拟集中是单例,主要是用来管理容器下各个Serivce组件的生命周期。
  • Service:
    Server 它将一个或多个连接器(Connector)组件绑定到一个单独的引擎(Engine)上。Service仅仅是一个分组结构,他只是充当架构的一个层面,它并不包含任何其他的功能。
  • Connector:
    连接器,处理与客户端的通信,它负责接收客户请求,以及向客户返回响应结果,每个连接器监控一个指定的IP及端口并通过指定的协议做出响应。可以配置多个连接器使用。
  • Engine:
    引擎,表示一个特定的 Service 的请求处理流水线,从连接器接收和处理所有的请求,将响应返回给适合的连接器,通过连接器传输给用户。在一个服务中(Service)只能有一个引擎。
  • Host:
    虚拟主机,Host 是 Engine 的子容器,一个 Engine 可以包含多个 Host。这个虚拟主机的作用就是运行应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们。
  • Context:
    他代表一个部署的 Web 应用程序本身,它具备了 Servlet 运行的基本环境。一个 Host 可以包含多个Context,每个 Context 都有一个唯一的路径。Context表示了一个应用的生命周期。

所有客户端的请求都会在连接器(Connector)接受,然后在引擎中(Engine),通过管道(PipeLine),在管道中可以加入各种自定义的阀门(Valve),做拦截,做过滤。所以 Engine 组件,在整次请求中,起着承前启后的关键作用。

下面,我们就着重分析 Engine 组件。

二、Engine 组件

1.核心类与依赖图

Engine 组件的核心类是 StandardEngine

该类的依赖图如下:

从图中可以看到,他也是通过 Lifecycle,来实现他的生命周期管理;并且 Engine 他还是一个容器,实现了Container
在这里插入图片描述

2.核心类源码分析

构造函数:

  1. public StandardEngine() {
  2. super();
  3. pipeline.setBasic(new StandardEngineValve());
  4. /* Set the jmvRoute using the system property jvmRoute */
  5. try {
  6. setJvmRoute(System.getProperty("jvmRoute"));
  7. } catch(Exception ex) {
  8. log.warn(sm.getString("standardEngine.jvmRouteFail"));
  9. }
  10. // By default, the engine will hold the reloading thread
  11. backgroundProcessorDelay = 10;
  12. }

可以看出来,主要是给StandardEngine的管道(pipeline)添加了阀门 Value

在 Tomcat 的源码中,以 Value 结尾的类,都是阀门,阀门就是用来提供一些功能的代码,封装成类

打开阀门的核心代码可以看到,他只是拿到 Host,并且调用他通道里面的 Value

  1. final class StandardEngineValve extends ValveBase {
  2. //------------------------------------------------------ Constructor
  3. public StandardEngineValve() {
  4. super(true);
  5. }
  6. @Override
  7. public final void invoke(Request request, Response response)
  8. throws IOException, ServletException {
  9. // Select the Host to be used for this Request
  10. Host host = request.getHost();
  11. if (host == null) {
  12. // HTTP 0.9 or HTTP 1.0 request without a host when no default host
  13. // is defined.
  14. // Don't overwrite an existing error
  15. if (!response.isError()) {
  16. response.sendError(404);
  17. }
  18. return;
  19. }
  20. if (request.isAsyncSupported()) {
  21. request.setAsyncSupported(host.getPipeline().isAsyncSupported());
  22. }
  23. // Ask this Host to process this request
  24. host.getPipeline().getFirst().invoke(request, response);
  25. }
  26. }

初始化方法 init:

既然 Engine 实现了 Lifecycle,那他自然也继承了里面的生命周期方法,在启动时,会触发 initInternal() 方法

源码中看到,在这里初始化以及获取了 Realm

Realm,可以翻译为 “ 域 “,在 Tomcat 中,他是一个存储用户名,密码以及和用户名相关联的角色的 “ 数据库 “

  1. @Override
  2. protected void initInternal() throws LifecycleException {
  3. // Ensure that a Realm is present before any attempt is made to start
  4. // one. This will create the default NullRealm if necessary.
  5. getRealm();
  6. super.initInternal();
  7. }

启动方法 start:

上面说到 Engine 实现了 Lifecycle,继承了他的生命周期方法,还有比较核心的 startInternal()

  1. @Override
  2. protected synchronized void startInternal() throws LifecycleException {
  3. // Log our server identification information
  4. if (log.isInfoEnabled()) {
  5. log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo()));
  6. }
  7. // Standard container startup
  8. super.startInternal();
  9. }

他调用了其父类的 startInternal()

  1. @Override
  2. protected synchronized void startInternal() throws LifecycleException {
  3. // Start our subordinate components, if any
  4. logger = null;
  5. getLogger();
  6. Cluster cluster = getClusterInternal();
  7. if (cluster instanceof Lifecycle) {
  8. ((Lifecycle) cluster).start();
  9. }
  10. Realm realm = getRealmInternal();
  11. if (realm instanceof Lifecycle) {
  12. ((Lifecycle) realm).start();
  13. }
  14. // Start our child containers, if any
  15. Container children[] = findChildren();
  16. List<Future<Void>> results = new ArrayList<>();
  17. for (Container child : children) {
  18. results.add(startStopExecutor.submit(new StartChild(child)));
  19. }
  20. MultiThrowable multiThrowable = null;
  21. for (Future<Void> result : results) {
  22. try {
  23. result.get();
  24. } catch (Throwable e) {
  25. log.error(sm.getString("containerBase.threadedStartFailed"), e);
  26. if (multiThrowable == null) {
  27. multiThrowable = new MultiThrowable();
  28. }
  29. multiThrowable.add(e);
  30. }
  31. }
  32. if (multiThrowable != null) {
  33. throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
  34. multiThrowable.getThrowable());
  35. }
  36. // Start the Valves in our pipeline (including the basic), if any
  37. if (pipeline instanceof Lifecycle) {
  38. ((Lifecycle) pipeline).start();
  39. }
  40. setState(LifecycleState.STARTING);
  41. // Start our thread
  42. if (backgroundProcessorDelay > 0) {
  43. monitorFuture = Container.getService(ContainerBase.this).getServer()
  44. .getUtilityExecutor().scheduleWithFixedDelay(
  45. new ContainerBackgroundProcessorMonitor(), 0, 60, TimeUnit.SECONDS);
  46. }
  47. }

这一大段代码中,有几个比较核心的地方:

  • 遍历找到其所有子容器,并启动他们

    Container children[] = findChildren();
    List> results = new ArrayList<>();
    for (Container child : children) {

    1. results.add(startStopExecutor.submit(new StartChild(child)));

    }

  • 启动他(Engine )的管道,并执行管道里面的阀门

    if (pipeline instanceof Lifecycle) {

    1. ((Lifecycle) pipeline).start();

    }

  • 调用监听事件

在父类的 startInternal() 方法中,用下面这行,调用了 LifecycleBase 里面的方法

  1. setState(LifecycleState.STARTING);

最终定位到,这个方法,调用其注册的监听事件

  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. }

传进来的,是 EngineConfig ,他实现了 LifecycleListener ,其监听器处理逻辑也很简单,只是记录一下操作日志


总结

欢迎指出我的错误!

发表评论

表情:
评论列表 (有 0 条评论,159人围观)

还没有评论,来说两句吧...

相关阅读

    相关 TOMCAT架构分析

    虽然分析过源码,但一直没时间,先贴一片别人的吧,备忘。   TOMCAT源码分析(启动框架) 前言:    本文是我阅读了TOMCAT源码后的一些心得。 主要是讲解

    相关 Tomcat--架构

    Tomcat架构 HTTP工作原理 HTTP协议是浏览器与服务器之间的数据传送协议。作为应用层协议,HTTP是基于TCP/IP协议来传递数据的(HTTP文件、图片、