作者简介:大家好,我是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注解 && 继承自HttpServlet
for (Class<?> clazz : servletList) {
boolean hasMyWebServletAnnotation = clazz.isAnnotationPresent(MyWebServlet.class);
boolean extendsHttpServlet = HttpServlet.class.isAssignableFrom(clazz);
if (hasMyWebServletAnnotation && extendsHttpServlet) {
// 确定是一个Servlet,为它创建实例并调用init
HttpServlet servletObj = (HttpServlet) clazz.newInstance();
servletObj.init();
}
}
}
private static List<Class<?>> scanServletsInPath() {
// 假装扫描到了Class
return Arrays.asList(BookServlet.class, OtherClass.class);
}
}
/**
* 山寨的Servlet接口,你可以在JDK的javax包下找到正版的Servlet,它定义了5个生命周期方法
* 这里我们只定义一个init方法,其他方法同理,不做演示
*/
interface Servlet {
void init();
}
/**
* 模拟javax包的GenericServlet
*/
abstract class GenericServlet implements Servlet {
@Override
public 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
进群,大家一起学习,一起进步,一起对抗互联网寒冬