在java web开发中,相较于传统的Spring,Spring Boot带来的一大好处是其内置的Servlet容器。在这个特性的帮助下,使得开发无需额外配置外部的Servlet容器,只需要一个Application类即可启动一个内置容器,这在微服务的开发,部署中尤为重要,带来了更多地便利性。
Apache Tomcat 作为大多数公司使用的Servlet容器,同时也是Spring Boot的默认内置容器。
在传统的外置Tomcat的情况下,我们通常把我们需要部署的项目放在/webapp目录下,这样Tomcat就可以检测到我们的项目进行加载部署。但是在Spring Boot中,这一步又是如何完成的呢?
tomcat类加载器
对Tomcat稍有理解的开发人员应该知道,Tomcat内部实现了自己的类加载器,用来打破双亲委派机制。
上图就是一个Tomcat启动后的类加载器图。
其中最顶层的BootStrapClassLoader,ExtClassLoader,AppClassLoader是java自身的类加载器。而其后的加载器则全部是Tomcat自己实现的类加载器。
这里不花费太多的篇幅来论述这些加载器的原理,源码讲解,只简单的说一下。
可以看到上图中,commomLoader,catalinaLoader,sharedLoader的首字母没有大写,这是由于他们实际上并不是一个新类,他们的实现都是JDK中的URLClassLoader,他们只是作为Tomcat中的一个类的属性存在,分别负责加载不同路径的Class。但是在Tomcat 6.x后,Tomcat的开发者们把这3个不同的路径合并成了一个一个文件夹,既lib 文件夹。基于此,在默认的情况下,这3个loader实际上是指向同一个引用。
WebAppClassLoader加载的就是我们实际的应用的Class文件,它可以有多个。
更底层的JasperLoader对应的是JSP编译后的Class文件,每一个JSP对应一个JasperLoader。
在这个架构中,WebAppClassLoader的上层都是遵循双亲委派机制的,他们的实现是为了加载一些Tomcat自身需要的Class,或者所有webApp都需要的Class。WebAppClassLoader这个加载器重写了方法,打破了双亲委派机制。到达这个类加载器时,它会首先判断能否使用自身加载,只有在无法使用自身去加载的时候才会把这个任务抛向更上层。至于JasperLoader的出现是为了实现JSP的热加载,每个JSP对应一个JasperLoader,当检测到一个JSP进行了修改,Tomcat就会把这个JSP对应的JasperLoader的抛弃,重新新建一个JasperLoader加载这个JSP,以此来实现热加载。