Tomcat源码学习 - 环境搭建

一. 源码下载

PS: 多图预警

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

二. 项目导入

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

然后进入 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引入项目

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

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

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

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

三. 乱码的原因

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

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

在这里我们可以看到,通过 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 按钮跳转进到对应的具体实现方法中

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

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

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

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

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

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

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

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

四. 解决乱码

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

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

    ↓

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

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

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

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

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

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

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

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

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

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

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

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

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

现在就大公告成拉!!!

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

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