Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?

使用idea开发工具调试代码的时候,如果是java的web项目,使用的是tomcat作为web容器,打断点debug调试跟踪,当跟踪到org.apache.catalina包下的时候,则无法进入,这是因为idea运行的tomcat是通过插件的方式集成的,tomcat里面的lib包不再项目的依赖路径中,所以不能跟踪进去

首先在自己项目中被tomcat回调的接口实现类中,标记一个断点信息,通过idea启动web项目,当出现如图所示的断点信息的时候,因为断点位置标记的是tomcat回调的接口类,所以按照调用堆栈网上则是tomcat内部代码,但此时双击org.apache.catalina包下面的类名,是没有任何反应的,因为我们还没有将tomcat对应的依赖文件添加到classpath下面

添加依赖

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-catalina</artifactId>
    <version>8.5.55</version>
    <scope>provided</scope>
</dependency>

因为运行时使用的是tomcat的lib目录下面的jar文件,所以此处的scope使用provided方式

下面就可以进入到tomcat源码调试了

tomcat启动日志是怎么执行打出来的?

03-Jun-2020 10:31:30.929 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Server.服务器版本: Apache Tomcat/8.5.55
03-Jun-2020 10:31:30.938 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 服务器构建:        May 5 2020 22:10:54 UTC
03-Jun-2020 10:31:30.938 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 服务器版本号(:     8.5.55.0
03-Jun-2020 10:31:30.938 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 操作系统名称:      Windows 10
03-Jun-2020 10:31:30.938 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log OS.版本:           10.0
03-Jun-2020 10:31:30.938 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 架构:              amd64
03-Jun-2020 10:31:30.939 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Java 环境变量:     C:\Program Files\Java\jdk1.8.0_212\jre
03-Jun-2020 10:31:30.939 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log Java虚拟机版本:    1.8.0_212-b10
03-Jun-2020 10:31:30.939 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log JVM.供应商:        Oracle Corporation
03-Jun-2020 10:31:30.939 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:     C:\Users\Administrator\.IntelliJIdea2018.3\system\tomcat\Unnamed_spring-shiro-training
03-Jun-2020 10:31:30.939 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:     D:\tomcat8.5.55\apache-tomcat-8.5.55

通过定位到 VersionLoggerListener 日志可以查看到

private void log() {
     
    log.info(sm.getString("versionLoggerListener.serverInfo.server.version",
            ServerInfo.getServerInfo()));
    log.info(sm.getString("versionLoggerListener.serverInfo.server.built",
            ServerInfo.getServerBuilt()));
    log.info(sm.getString("versionLoggerListener.serverInfo.server.number",
            ServerInfo.getServerNumber()));
    log.info(sm.getString("versionLoggerListener.os.name",
            System.getProperty("os.name")));
    log.info(sm.getString("versionLoggerListener.os.version",
            System.getProperty("os.version")));
    log.info(sm.getString("versionLoggerListener.os.arch",
            System.getProperty("os.arch")));
    log.info(sm.getString("versionLoggerListener.java.home",
            System.getProperty("java.home")));
    log.info(sm.getString("versionLoggerListener.vm.version",
            System.getProperty("java.runtime.version")));
    log.info(sm.getString("versionLoggerListener.vm.vendor",
            System.getProperty("java.vm.vendor")));
    log.info(sm.getString("versionLoggerListener.catalina.base",
            System.getProperty("catalina.base")));
    log.info(sm.getString("versionLoggerListener.catalina.home",
            System.getProperty("catalina.home")));


    if (logArgs) {
     
        List<String> args = ManagementFactory.getRuntimeMXBean().getInputArguments();
        for (String arg : args) {
     
            log.info(sm.getString("versionLoggerListener.arg", arg));
        }
    }


    if (logEnv) {
     
        SortedMap<String, String> sortedMap = new TreeMap<>(System.getenv());
        for (Map.Entry<String, String> e : sortedMap.entrySet()) {
     
            log.info(sm.getString("versionLoggerListener.env", e.getKey(), e.getValue()));
        }
    }


    if (logProps) {
     
        SortedMap<String, String> sortedMap = new TreeMap<>();
        for (Map.Entry<Object, Object> e : System.getProperties().entrySet()) {
     
            sortedMap.put(String.valueOf(e.getKey()), String.valueOf(e.getValue()));
        }
        for (Map.Entry<String, String> e : sortedMap.entrySet()) {
     
            log.info(sm.getString("versionLoggerListener.prop", e.getKey(), e.getValue()));
        }
    }
}

发现是通过键值对的方式获取的,再通过字符串全局搜索发现
Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第1张图片
但是匹配的是英文,那么中文是怎么打出来的呢?

最后通过调试发现找的是这个
Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第2张图片
类似上面的东西,调试的时候发现tocmat的东西启动还是相当多的
且看下面这个
Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第3张图片
idea tomcat启动后的数据

03-Jun-2020 10:31:30.939 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Djava.util.logging.config.file=C:\Users\Administrator\.IntelliJIdea2018.3\system\tomcat\Unnamed_spring-shiro-training\conf\logging.properties
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-agentlib:jdwp=transport=dt_socket,address=127.0.0.1:52290,suspend=y,server=n
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-javaagent:C:\Users\Administrator\.IntelliJIdea2018.3\system\captureAgent\debugger-agent.jar
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dfile.encoding=UTF-8
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dcom.sun.management.jmxremote=
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dcom.sun.management.jmxremote.port=1099
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dcom.sun.management.jmxremote.ssl=false
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dcom.sun.management.jmxremote.password.file=C:\Users\Administrator\.IntelliJIdea2018.3\system\tomcat\Unnamed_spring-shiro-training\jmxremote.password
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dcom.sun.management.jmxremote.access.file=C:\Users\Administrator\.IntelliJIdea2018.3\system\tomcat\Unnamed_spring-shiro-training\jmxremote.access
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Djava.rmi.server.hostname=127.0.0.1
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Djdk.tls.ephemeralDHKeySize=2048
03-Jun-2020 10:31:30.940 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Djava.protocol.handler.pkgs=org.apache.catalina.webresources
03-Jun-2020 10:31:30.941 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dignore.endorsed.dirs=
03-Jun-2020 10:31:30.941 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dcatalina.base=C:\Users\Administrator\.IntelliJIdea2018.3\system\tomcat\Unnamed_spring-shiro-training
03-Jun-2020 10:31:30.941 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Dcatalina.home=D:\tomcat8.5.55\apache-tomcat-8.5.55
03-Jun-2020 10:31:30.941 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:-Djava.io.tmpdir=D:\tomcat8.5.55\apache-tomcat-8.5.55\temp

以上还只是基本的环境配置等启动
然后是准备链接到tomcat服务

03-Jun-2020 10:31:30.941 信息 [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent 使用APR版本[1.7.0]加载了基于APR的Apache Tomcat本机库[1.2.24]03-Jun-2020 10:31:30.941 信息 [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR功能:IPv6[true]、sendfile[true]、accept filters[false]、random[true]03-Jun-2020 10:31:30.941 信息 [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL配置:useAprConnector[false],useOpenSSL[true]
03-Jun-2020 10:31:30.944 信息 [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL成功初始化 [OpenSSL 1.1.1g  21 Apr 2020]
03-Jun-2020 10:31:31.032 信息 [main] org.apache.coyote.AbstractProtocol.init 初始化协议处理器 ["http-nio-8080"]
03-Jun-2020 10:31:31.046 信息 [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
03-Jun-2020 10:31:31.055 信息 [main] org.apache.catalina.startup.Catalina.load Initialization processed in 175489 ms
03-Jun-2020 10:31:31.080 信息 [main] org.apache.catalina.core.StandardService.startInternal 正在启动服务[Catalina]
03-Jun-2020 10:31:31.080 信息 [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.55
03-Jun-2020 10:31:31.089 信息 [main] org.apache.coyote.AbstractProtocol.start 开始协议处理句柄["http-nio-8080"]
03-Jun-2020 10:31:31.102 信息 [main] org.apache.catalina.startup.Catalina.start Server startup in 47 ms

tomat启动主要是在Catalina中
Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第4张图片
Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第5张图片
然后是
Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第6张图片
启动


/**
* Await and shutdown.
*/
public void await() {
     


    getServer().await();


}

其实tomcat启动本质上就是socket的服务器罢了

@Override
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;
                long acceptStartTime = System.currentTimeMillis();
                try {
     
                    socket = serverSocket.accept(); //一旦accecpt后面就开始执行了
                    socket.setSoTimeout(10 * 1000);  // Ten seconds
                    stream = socket.getInputStream();
                } catch (SocketTimeoutException ste) {
     
                    // This should never happen but bug 56684 suggests that
                    // it does.
                    log.warn(sm.getString("standardServer.accept.timeout",
                            Long.valueOf(System.currentTimeMillis() - acceptStartTime)), ste);
                    continue;
                } catch (AccessControlException ace) {
     
                    log.warn(sm.getString("standardServer.accept.security"), ace);
                    continue;
                } catch (IOException e) {
     
                    if (stopAwait) {
     
                        // Wait was aborted with socket.close()
                        break;
                    }
                    log.error(sm.getString("standardServer.accept.error"), 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(sm.getString("standardServer.accept.readError"), e);
                        ch = -1;
                    }
                    // Control character or EOF (-1) terminates loop
                    if (ch < 32 || ch == 127) {
     
                        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(sm.getString("standardServer.invalidShutdownCommand", command.toString()));
        }
    } finally {
     
        ServerSocket serverSocket = awaitSocket;
        awaitThread = null;
        awaitSocket = null;


        // Close the server socket and return
        if (serverSocket != null) {
     
            try {
     
                serverSocket.close();
            } catch (IOException e) {
     
                // Ignore
            }
        }
    }
}

Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第7张图片
tomcat容器启动之后,下面就是Springmvc模块的内容了
Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第8张图片
Idea中tocmat启动 源码调试,如何进入到tomcat内部进行调试?_第9张图片

你可能感兴趣的:(spring,tomcat调试,源码分析,spring,catalina,java)