• Tomcat - 初始化流程分析


    前言

    Tomcat - 源码阅读环境搭建 这篇文章中我们搭建了 Tomcat 源码阅读的环境;在 Tomcat - 从源码阅读中分析核心组件 中我们分析了 Tomcat 的核心组件及其依赖关系。接下来我们就一起来跟踪一下 Tomcat 源码中的初始化流程

    分析

    org.apache.catalina.startup.Bootstrap 入口类

    public static void main(String args[]) {
    
        synchronized (daemonLock) {
            if (daemon == null) {
                // 首先会初始化一个 Bootstrap 对象,初始化一些静态的变量和代码块
                Bootstrap bootstrap = new Bootstrap();
                try {
                	// 1、核心流程
                    bootstrap.init();
                }
                ...
                daemon = bootstrap;
            }
            ...
        }
    
        try {
        	// 默认命令为 start
            String command = "start";
            ...
            } else if (command.equals("start")) {
                // 调用 Catalina 实例的 setAwait 方法,参数为 true
                daemon.setAwait(true);
                // 2、核心流程,利用反射调用 Catalina 实例的 load 无参方法
                daemon.load(args);  // 核心组件初始化流程(Server、Connector、Engine、Service、Endpoint、ProtocolHandle等),并绑定好了端口,准备接收数据
                // 3、利用反射调用 Catalina 实例的 start 方法
                daemon.start();
                // 利用反射调用 Catalina 实例的 getServer 方法
                if (null == daemon.getServer()) {
                    System.exit(1);
                }
            }
            ...
    }
    
    • 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

    1、init() 方法

    public void init() throws Exception {
    
       	// 初始化类加载器
        initClassLoaders();
    
        ...
        // 获取到 org.apache.catalina.startup.Catalina 类
        Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        // 初始化 Catalina 实例
        Object startupInstance = startupClass.getConstructor().newInstance();
    
       	...
        // 下面这一块是调用 Catalina 类中的 setParentClassLoader 方法,把 sharedLoader 作为方法入参
        {
            String methodName = "setParentClassLoader";
            Class<?> paramTypes[] = new Class[1];
            paramTypes[0] = Class.forName("java.lang.ClassLoader");
            Object paramValues[] = new Object[1];
            paramValues[0] = sharedLoader;
            Method method =
                startupInstance.getClass().getMethod(methodName, paramTypes);
            method.invoke(startupInstance, paramValues);
        }
        // startupInstance 是初始化后的 Catalina,并且设置了其中的 parentClassLoader 属性
        catalinaDaemon = startupInstance;
    }
    
    • 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
    1.1、initClassLoaders() 方法
    ClassLoader commonLoader = null;
    ClassLoader catalinaLoader = null;
    ClassLoader sharedLoader = null;
    
    /**
     * 初始化 3 种类加载器
     */
    private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            if (commonLoader == null) {
                // no config file, default to this loader - we might be in a 'single' env.
                commonLoader = this.getClass().getClassLoader();
            }
            catalinaLoader = createClassLoader("server", commonLoader);
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            handleThrowable(t);
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2、load() 方法

    private void load(String[] arguments) throws Exception {
    
       	// Call the load() method
        String methodName = "load";
        ...
        // 调用 Catalina 的 load 无参方法
        Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes);
        method.invoke(catalinaDaemon, param);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 查看 Catalinaload() 方法
    public void load() {
    
      	...
    
        // Parse main server.xml
        // 1、解析 server.xml 配置文件,并创建了 Server 对象
        parseServerXml(true);
        Server s = getServer();
        if (s == null) {
            return;
        }
    
        ...
    
        // Start the new server
        try {
            // 这里初始化好了 service、engine、connector
            // 2、核心流程
            getServer().init(); // 初始化 server
        }
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    2.1、parseServerXml() 方法
    protected void parseServerXml(boolean start) {
     	// Set configuration source
        // 首先获取到默认的配置文件 conf/server.xml
        ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
        File file = configFile();
        ...
    
        ServerXml serverXml = null;
    
        if (serverXml != null) {
            serverXml.load(this);
        } else {
            try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
                // Create and execute our Digester
                // 1、创建 解析器,来解析 xml 文件
                Digester digester = start ? createStartDigester() : createStopDigester();
                InputStream inputStream = resource.getInputStream();
                InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
                inputSource.setByteStream(inputStream);
                digester.push(this);
                ...
                // 2、核心流程,解析到了 Server
                digester.parse(inputSource);
                ...
            }
            ...
        }
    }
    
    • 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
    2.2.1、createStartDigester() 创建解析器
    protected Digester createStartDigester() {
      	// Initialize the digester
        Digester digester = new Digester();
    	...
        // Configure the actions we will be using
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
    	...
        digester.addObjectCreate("Server/GlobalNamingResources",
                                 "org.apache.catalina.deploy.NamingResourcesImpl");
    	...
        digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");
    	...
        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());
    	...
        digester.addRule("Server/Service/Connector", new AddPortOffsetRule());
    	...
        // When the 'engine' is found, set the parentClassLoader.
        digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(parentClassLoader));
    	...
        return digester;
    
    }
    
    • 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
    2.2.2、Digesterparse() 方法

    server.xml 中解析出 Server 对象

    public Object parse(InputSource input) throws IOException, SAXException {
      	configure();
        getXMLReader().parse(input); // 获取到 XMLReader,并解析 server.xml
        return root;    // 封装为 Catalina 后返回
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • getXMLReader() 获取 XMLReader
    public XMLReader getXMLReader() throws SAXException {
      	if (reader == null) {
      		// 1、getParser
      		// 2、getXMLReader
            reader = getParser().getXMLReader();
        }
    
        ...
        return reader;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    getParser() 获取解析器:

    public SAXParser getParser() {
    
      	// Return the parser we already created (if any)
        if (parser != null) {
            return parser;
        }
    
        // Create a new parser
        try {
        	// 工厂模式
            parser = getFactory().newSAXParser();
        } catch (Exception e) {
            log.error(sm.getString("digester.createParserError"), e);
            return null;
        }
    
        return parser;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    获取到工厂类:

    public SAXParserFactory getFactory() throws SAXNotRecognizedException, SAXNotSupportedException,
                ParserConfigurationException {
    
    	if (factory == null) {
    		// 返回工厂类 SAXParserFactory 的实例
            factory = SAXParserFactory.newInstance();
    
            ...
        }
        return factory;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    newInstance()

    public static SAXParserFactory newInstance() {
     	return FactoryFinder.find(
                /* The default property name according to the JAXP spec */
                SAXParserFactory.class,
                /* The fallback implementation class name */
                "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    getFactory() 返回的是 com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl 实现类。

    那么 parser 通过 SAXParserFactoryImplnewSAXParser() 返回:

    public SAXParser newSAXParser()
            throws ParserConfigurationException
    {
        SAXParser saxParserImpl;
        try {
        	// 调用构造函数创建,会初始化 xmlReader 为 JAXPSAXParser
            saxParserImpl = new SAXParserImpl(this, features, fSecureProcess);
        } catch (SAXException se) {
            // Translate to ParserConfigurationException
            throw new ParserConfigurationException(se.getMessage());
        }
        return saxParserImpl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    getXMLReader() 即返回 SAXParserImpl 中的 xmlReader,在构造函数中初始化为 JAXPSAXParser

    SAXParserImpl(SAXParserFactoryImpl spf, Map<String, Boolean> features, boolean secureProcessing)
            throws SAXException
    {
        fSecurityManager = new XMLSecurityManager(secureProcessing);
        fSecurityPropertyMgr = new XMLSecurityPropertyManager();
        // Instantiate a SAXParser directly and not through SAX so that we use the right ClassLoader
        xmlReader = new JAXPSAXParser(this, fSecurityPropertyMgr, fSecurityManager);
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • parse(input) 解析 server.xml 文件流

    这里就是根据定义好的解析规则来解析并返回一个 Catalina,同时根据 server.xml 中的内容生成了 Server 对象(这个解析过程并非主要流程,这里也不展开了,感兴趣的朋友可以自己 Debug 看一下):

    在这里插入图片描述

    2.2、Serverinit() 方法

    Tomcat - 从源码阅读中分析核心组件 这篇文章中我们知道,Server 等组件都是有生命周期的,实现了 Lifecycle 接口:

    • LifecycleBase 使用模板设计模式,定义了执行流程,由子类实现具体逻辑
    @Override
    public finalsynchronized void init() throws LifecycleException {
        ...
    
        try {
            setStateInternal(LifecycleState.INITIALIZING, null, false);
            // 核心流程,由子类实现具体初始化过程
            initInternal();
            setStateInternal(LifecycleState.INITIALIZED, null, false);
        }
        ...
    }
    
    protected abstract void initInternal() throws LifecycleException;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 子类 StandardServer 实现 initInternal() 方法:
    @Override
    protected void initInternal() throws LifecycleException {
    
        super.initInternal();
    
        ...
        // Initialize our defined Services
        for (Service service : services) {
        	// 初始化 Server 的时候,会初始化 Service
            service.init();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    2.2.1、Serviceinit() 方法
    • 继续查看 Serviceinit() 方法,同样是由实现类 StandardService 实现具体的 initInternal() 模板方法:
    @Override
    protected void initInternal() throws LifecycleException {
    
        super.initInternal();
    
        // 初始化 service 之前需要先初始化 engine
        if (engine != null) {
            engine.init();
        }
    
        // Initialize any Executors
        for (Executor executor : findExecutors()) {
            if (executor instanceof JmxEnabled) {
                ((JmxEnabled) executor).setDomain(getDomain());
            }
            executor.init();
        }
    
        // Initialize mapper listener
        mapperListener.init();
    
        // Initialize our defined Connectors
        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                // 会初始化 endpoint,并绑定好端口
                connector.init();
            }
        }
    }
    
    • 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
    2.2.2、Engineinit() 方法

    Engine 中可能会处理一些 Realm

    @Override
    protected void initInternal() throws LifecycleException {
        // Ensure that a Realm is present before any attempt is made to start
        // one. This will create the default NullRealm if necessary.
        getRealm();
        super.initInternal();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2.2.3、Connectorinit() 方法
    @Override
    protected void initInternal() throws LifecycleException {
    
        super.initInternal();
    
        ...
    
        try {
            // 协议处理器初始化
            protocolHandler.init();
        }
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    2.2.4、ProtocolHandlerinit() 方法

    ProtocolHandlerinit() 方法由抽象类 AbstractProtocol 实现:

    @Override
    public void init() throws Exception {
        ...
    
        String endpointName = getName();
        endpoint.setName(endpointName.substring(1, endpointName.length()-1));
        endpoint.setDomain(domain);
    
        // 端点初始化
        endpoint.init();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    2.2.5、AbstractEndpointinit() 方法
    public final void init() throws Exception {
    	if (bindOnInit) {
            bindWithCleanup();
            bindState = BindState.BOUND_ON_INIT;
        }
        if (this.domain != null) {
            // Register endpoint (as ThreadPool - historical name)
            oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
            Registry.getRegistry(null, null).registerComponent(this, oname, null);
    
            ObjectName socketPropertiesOname = new ObjectName(domain +
                    ":type=SocketProperties,name=\"" + getName() + "\"");
            socketProperties.setObjectName(socketPropertiesOname);
            Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);
    
            for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
                registerJmx(sslHostConfig);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    private void bindWithCleanup() throws Exception {
       try {
       		// 由实现类实现
            bind();
        }
        ...
    }
    
    public abstract void bind() throws Exception;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    bind() 由实现类 NioEndpoint 实现:

    @Override
    public void bind() throws Exception {
        // 初始化 ServerSocket
        initServerSocket();
    
        setStopLatch(new CountDownLatch(1));
    
        // Initialize SSL if needed
        initialiseSsl();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    protected void initServerSocket() throws Exception {
      	...
        } else {
            // java nio 中的 ServerSocketChannel 打开一个 channel
            serverSock = ServerSocketChannel.open();
            socketProperties.setProperties(serverSock.socket());
            InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
            // 绑定端口,到这里为止还只是初始化 ServerSocket。并没有准备好开始接收请求
            serverSock.bind(addr, getAcceptCount());
        }
        serverSock.configureBlocking(true); //mimic APR behavior
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    到此为止,已经走到了 Server 初始化栈的顶端,表示相关的组件 ServiceEngineConnector 等都已经初始化完了。

    同时也是终于执行完了 Catalina 对象的 load() 方法,整个过程还是比较长的,而且涉及到的概念比较多,又使用了设计模式,所以这块可能需要多看几遍才能理解。

    3、start() 方法

    上一部分中已经完成了 Bootstrap 对象的 load() 方法,同时也初始化好了 Server 对象。在下一篇文章 Tomcat - 启动流程分析 中我们再来分析 启动流程

  • 相关阅读:
    8条IM即时通讯开发iOS端移动网络调优建议
    【一起学Rust】Rust介绍与开发环境搭建
    AI绘画关键词:小龙女
    WinRAR CVE-2023-40477代码执行漏洞复现
    C++中虚继承时的构造函数
    主数据工作交接
    一篇文章让你搞懂线程
    github参与开源项目并上传修改
    JavaScript常用工具函数汇总(一)
    记一次 .NET某设备监控自动化系统 CPU爆高分析
  • 原文地址:https://blog.csdn.net/qiaohao0206/article/details/126143166