深入理解Servlet(中)

作者简介:大家好,我是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

进群,大家一起学习,一起进步,一起对抗互联网寒冬
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值