从Servlet、Servlet容器及Web容器的演进历程总结框架设计的套路

文章讲述了Web技术从静态页面到动态交互的发展,引出了CGI的出现和其局限性,进而介绍了Servlet和Servlet容器的概念,以及它们如何解耦HTTP服务器和业务逻辑。Servlet规范使得不同Web中间件间可以互换,提升了灵活性。最后,文章强调了接口和抽象类在框架设计中的重要性,并以Servlet为例阐述了这一设计模式。
摘要由CSDN通过智能技术生成

Web架构演进历程

早期的Web技术主要用于浏览静态页面,首先浏览器发起HTTP请求,请求一些静态资源,这时候需要一个服务器来处理HTTP请求,并且将相应的静态资源返回。这个服务器叫HTTP服务器。

简单点说就是解析请求,然后得知需要服务器上面哪个文件夹下哪个名字的静态文件,找到返回即可。

而随着互联网的发展,交互越发得重要,用户已经不满足于仅浏览静态页面。用户需要一些交互操作,获取一些动态结果。业务变得复杂,需要我们编写代码来处理诸多业务,需要根据HTTP请求调用不同的业务逻辑来响应。如果基于HTTP协议实现服务器端软件增强功能太过复杂,所以需要一些扩展机制来实现用户想要的功能。

早期使用的Web服务器扩展机制是CGI(Common Gateway Interface,公共网关接口)。

CGI程序在一定程度上解决了用户需求。不过还存在一些不足之处,如CGI程序编写困难,响应时间较长,以进程方式运行导致性能受限。我们迫切需要一种新的抽象,在克服CGI程序缺点的同时,去实现业务代码跟HTTP服务器的解耦

业务千千万,所以需要规定一个接口,所以业务类都实现这个接口这样才好对接,这就是接口的含义。这个接口就是Servlet规范,Servlet指代的是实现Servlet接口的那些业务类。而Servlet容器其实就是用来管理和加载这些Servlet类的,根据HTTP请求找到对应的Servlet类就是 Servlet容器要做的事情。

这里还能再抽一层?业务实现写在Servlet类中,而管理和加载Servlet类和具体的业务实现是没关系的,没必要把Servlet容器做的事情和具体的业务耦合起来,业务反正照着Servlet接口实现就行,这样Servlet容器就可以加载并管理它。

把HTTP请求和Servlet的对应关系也抽象出来,就是web.xml了,咱们在配置里面告诉Servlet容器对应关系即可,当HTTP请求进来时,Servlet容器会根据映射关系找到对应的Servlet类。

其实Servlet接口和Servlet容器这一整套包括目录命名合起来就叫Servlet 规范。所有相关的中间件按照Servlet规范实现,我们也按Servlet规范来实现业务代码,这样我们就能在不同场景选择不同的Web中间件。规范的目的就是为了对接方便,减少对接成本。

至此HTTP服务器、Servlet 、Servlet容器都划分清晰了。而Web容器其实就是HTTP 服务器 + Servlet容器,因为单单Servlet容器没有解析HTTP协议的能力。

所以把Tomcat、Jetty等实现了HTTP服务器和Servlet容器的功能,称之为Web容器。

架构的设计就是一系列相关的抽象。先是抽象出HTTP服务器,用来通信和解析协议。再因为业务的复杂,为了不和HTTP服务耦合又抽象了一层Servlet。由Servlet容器来专职负责加载和管理Servlet,将请求转发到指定的Servlet实现类。然后我们安心的开发业务即可。

因为抽象所以灵活易扩展,比如现在是HTTP1.1服务,可以换成HTTP 2。

现在用Tomcat来作为Servlet容器,也可以换成Jetty。

现在用原生的实现Servlet来做业务,也可以换成Spring MVC。

随意变更,因为都抽象出来了,就很好替换,只要遵循约定的接口实现即可。

框架设计的套路

从以上架构演进历程,也可以总结出框架设计的套路:接口和抽象类。

这是所有中间件设计必用的套路,当然我们自己的代码也可以这样用。

先定义一个接口来约定一些动作,能做什么

然后再定义一个抽象类来实现这个接口,用来实现一些通用的逻辑,做到代码的复用

然后再搞一些常用的实现类继承抽象类,方便开发者的使用。剩下的就留给开发者自行扩展即可。

然后抽象类都会使用模板方法,也就是定义执行的流程,流程中的具体实现逻辑由子类自行实现。

这就是必用的套路:接口约束、抽象类完成代码复用(提供通用实现)、常用实现类方便直接使用、模板方法定义执行流程、剩下的自行扩展。

拿Servlet举例,首先定义Servlet接口。

public interface Servlet {
    void init(ServletConfig config) throws ServletException;
    ServletConfig getServletConfig();
    void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
    String getServletInfo();
    void destroy();
}

然后搞了个通用抽象类GenericServlet,不过这个抽象类逻辑比较简单。

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
  // 省略一些...
   @Override
    public ServletConfig getServletConfig() {
        return config;
    }
    @Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
// 省略一些...
}

然后又搞了个常用的HttpServlet继承了GenericServlet。

public abstract class HttpServlet extends GenericServlet {

    private static final long serialVersionUID = 1L;

    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
  // 省略一些...
}

套路就是这么个套路,计算机科学中的每个问题都可以用一间接层解决?是的,基本上所有问题抽象一层都能解决。如果一层不够,那就两层。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值