作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
上篇有一张图:
借助这张图,我们能够大致了解Tomcat作为web容器是如何创建和管理web组件的(Filter、Servlet、Listener)。此外我们还了解到这些组件都是有生命周期的,也就是在特定的时期调用生命周期方法完成一些事,比如初始化或对象销毁。
这一篇,我们打算换种形式,将上面的那张图用Java代码重新“画”一遍,造一个山寨版的Tomcat容器来初始化山寨版的Servlet。如此一来既能加深大家对于Tomcat和Servlet的理解,还能复习Java的基础知识。由于现在Java开发都是以注解形式为主导,所以我们打算抛弃传统的<servlet>标签,使用自定义的@MyWebServlet注解标识Servlet类(Servlet3.0开始推出@WebServlet标注Servlet)。
大家可以把下面的代码拷贝到SpringBoot项目的Test目录下,然后观察并运行。
/*** Servlet容器*/
public class ServletContainer {public static void main(String[] args) throws IllegalAccessException, InstantiationException {// 模拟容器的扫描过程,假设得到了所有Class(包含Servlet类和普通类,普通类是用来做对照的,实际开发项目中肯定不全是Servlet)List<Class<?>> servletList = scanServletsInPath();System.out.println("在Container中线程执行到main方法啦:" + Thread.currentThread().getName());// 从中选出Servlet:类上标注了@MyWebServlet注解 && 继承自HttpServletfor (Class<?> clazz : servletList) {boolean hasMyWebServletAnnotation = clazz.isAnnotationPresent(MyWebServlet.class);boolean extendsHttpServlet = HttpServlet.class.isAssignableFrom(clazz);if (hasMyWebServletAnnotation && extendsHttpServlet) {// 确定是一个Servlet,为它创建实例并调用initHttpServlet servletObj = (HttpServlet) clazz.newInstance();servletObj.init();}}}private static List<Class<?>> scanServletsInPath() {// 假装扫描到了Classreturn Arrays.asList(BookServlet.class, OtherClass.class);}
}/*** 山寨的Servlet接口,你可以在JDK的javax包下找到正版的Servlet,它定义了5个生命周期方法* 这里我们只定义一个init方法,其他方法同理,不做演示*/
interface Servlet {void init();
}/*** 模拟javax包的GenericServlet*/
abstract class GenericServlet implements Servlet {@Overridepublic void init() {System.out.println("线程执行到GenericServlet.init方法啦:" + Thread.currentThread().getName());System.out.println("如果子类不重写,那么你就会看到GenericServlet的init被调用");System.out.println("由" + this.getClass().getName() + "调用");}
}/*** 模拟javax包的HttpServlet*/
abstract class HttpServlet extends GenericServlet {
}/*** 很多时候我们会抽取一个BaseServlet,把公共的代码抽取一下,这里不做任何处理,就是一个空的类*/
class BaseServlet extends HttpServlet {
}/*** 假设这是我们自己写的Servlet,类似于BookController* 使用@MyWebServlet标识这是一个Servlet,让Tomcat容器帮我们创建和管理*/
@MyWebServlet(name = "bookServlet")
class BookServlet extends BaseServlet {
}/*** 用来做对照,没什么意义*/
class OtherClass {
}/*** 山寨版@WebServlet*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyWebServlet {String name() default "";
}
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
进群,大家一起学习,一起进步,一起对抗互联网寒冬