Tomcat源码学习 - 环境搭建

一. 源码下载

PS: 多图预警

在开始阅读源码之前,我们需要先构建一个环境,这样才能便于我们对源码进行调试,具体源码我们可以到官网进行下载(这里我以8.5.63版本为例)。

image

二. 项目导入

下载并解压 apache-tomcat-8.5.63-src.zip。

image

然后进入 apache-tomcat-8.5.63-src 目录,新增一个 pom.xml 文件



4.0.0

    org.apache.tomcat
apache-tomcat-8.5.63-src
    8.5
    Tomcat8.5



    
    
        javax.xml
        jaxrpc
        1.1
    
    
    
        javax.xml.soap
        javax.xml.soap-api
        1.4.0
    
    
    
        wsdl4j
        wsdl4j
        1.6.2
    
    
    
        org.eclipse.jdt.core.compiler
        ecj
        4.5.1
    
    
    
        ant
        ant
        1.7.0
    
    
    
        org.easymock
        easymock
        3.4
    


    
        
        Tomcat8.5
        java
        
            
                java
            
        
        
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.1
                
                    1.8
                    1.8
                    UTF-8
                
            
        
    


通过IDEA引入项目

image

打开项目之后,全局搜索一下 main 方法,找到 tomcat 的入口

image

一共有6个 main 方法,其中有一个 Bootstrap 类,翻译过来就是引导程序的意思,我们直接跳转到这个类过去,跑一下看看有没有什么问题。


image

项目启动成功了,控制台输出的信息有乱码,暂时不管,我们看看能不能访问到首页。

image

显示500状态码,给出的信息也很多是乱码,那我们来看一下是什么原因导致的吧。

三. 乱码的原因

找到最开始出现乱码的地方,选中这个类名,双击 Shift 键查找并跳转到对应方法处。

image
image

打个断点,然后开始 DEBUG,先一层层进入,跟踪下看看首次出现乱码的地方是在哪

image

在这里我们可以看到,通过 handleGetObject() 方法得到的对象是有乱码的情况,在这里打上一个断点,然后继续深入

先一层层进入,跟踪下看看首次出现乱码的地方是在哪

// Debug跳转线路
VersionLoggerListener.java
private void log(){ ... }

    ↓

StringManager.java
public String getString(String key){ ... }

    ↓

ResourceBundle.java
public final Object getObject(String key){ 
    Object obj = handleGetObject(key);
    ...
}

    ↓

protected abstract Object handleGetObject(String key);

    ↓

PropertyResourceBundle.java
public Object handleGetObject(String key){
    return lookup.get(key);
}

protected abstract Object handleGetObject(String key); 这是一个抽象方法,点击 Setp into 按钮跳转进到对应的具体实现方法中

image

在这个方法中我们可以看到他实际上是在一个 HashMap 中根据传入的 key 来获取对应的 value,选择该代码块,按 AIT + F8 进行查看

在这里插入图片描述

发现起因了,在这个 HashMap 中存储的 value 都是乱码的,才会导致后面调用到的地方显示的都是乱码

image

起因发现了,那么我们就得来找一下这个 HashMap 对象的 put 操作是在哪一处进行的,才好真正的解决问题。

选择 lookupCtrl + F 查找一下,找到一下两个方法,都给他打上断点,然后重启项目,看看具体是由哪个方法来实现的。

image

在这里我们可以看到他是通过输入流的形式来实现的,在下方的 Variables 窗口中可以看到 Properties 加载出来的数据已经是乱码的了

image

Frames 窗口点击上一栈帧,找到当前方法的调用入口,回溯上去找到 stream 的来源

image

image

image

按照上面给出的路径找到对应的文件,可以看到里面是 UTF-8 编码的中文字符。

image

文件编码没有问题,那么问题就是出在 is = classLoader.getResourceAsStream(resourceName); 这个方法上了,这时候我们想对他进行一个修改,发现该类是锁定状态,无法修改,只能看不能碰这有点难度呀~

四. 解决乱码

我们还得重新来一遍,看看这个配置信息再哪个可编辑的类中有使用,然后再进行修改

// Debug跳转线路
VersionLoggerListener.java
private void log(){ ... }

    ↓

StringManager.java
public String getString(String key){ ... }

我们可以看到再 StringManager 这个类中有一个获取的方法,再往下走就是加锁的类了,那么我们尝试着在这一层对该结果进行编码转换,看看效果如何

image

image

有效果,控制台这边显示的信息已经没有乱码了,再看一下页面这边如何


image
image

页面这边还是有一部分显示是乱码的,看来还有地方需要修改,继续找下看


image

通过查看控制台的错误信息,全局搜索一下该提示出现位置进行定位


image

跳转到对应位置,Ctrl + 左键 定位到调用的地方,在这里可以看到 error() 方法中有具体的一些信息参数,我们用老方法对这 e.getMessage 这个参数修改一下看

image

image

控制台的乱码解决了,可是页面这边的还是乱码,看来是找错地方了,再来!


image

image

根据页面的提示找到 JspCompilationContext 类的 compile 方法,逐行查看,找到出错的地方

image

看到这里有个 Localizer.getMessage() 方法用来获取信息的,跳进来看一下,果然是这里,找到地方了,直接办他!

image

image

重启项目,再次刷新查看效果,终于搞定了,不容易呀~


image

五. 解决 ‘无法为JSP编译类’ 异常

导致页面显示500状态码的原因是 Tomcat 源码中 jsp 引擎 Jasper 没有被初始化,从而无法编译处理 jsp (以为 jsp 是需要被转换成 servlet 进一步编译处理的),我们只需要在 Tomcat 的源码 ContextConfig 类的 configureStart 方法中把该引擎进行初始化即可,代码如下:

context.addServletContainerInitializer(new JasperInitializer(), null);
image

现在就大公告成拉!!!


image

我收集有众多的 计算机电子书籍,有需要的小伙伴自提哦~

你可能感兴趣的:(Tomcat源码学习 - 环境搭建)