为什么不应该重写service方法?

本篇博文为朋友推荐,本人觉得很好所以贡献出来,希望给大家有所帮助。由于我们也是获取于他人,不知道原作者是谁,如有侵权,请联系本人。

先来看一个具体的例子:
当时我正在看一篇大作,只见我右手F12熟练的打开了chrome的开发者工具,左手迅猛的按了几下F5,然后看到了这个结果。
在这里插入图片描述
聪明的你一定已经发现,除了第一个名为12_77118的请求返回状态为200,其他的都为304,那么200和304有什么区别呢?这个稍后解释。
一切从代码里面来,我们先抛开理论,看一个具体的code:
我编写了一个index.html,如下:

<html> 
<body> 
<h3>I'm a test page . </h3> 
<h3>I'm a test page . </h3> 
<h3>I'm a test page . </h3> 
<h3>I'm a test page . </h3> 
<h3>I'm a test page . </h3> 
<h3>I'm a test page . </h3> 
<h3>I'm a test page . </h3> 
</body> 
</html>

我们来访问这个页面看看
在这里插入图片描述
这是我第一次访问这个页面(表示本地并没有对这个文件的缓存):
我们来看看http请求和响应的消息头:
在这里插入图片描述

为了作为对比,我们再F5刷新一次:
在这里插入图片描述
这次请求的头信息中多了一条If-Modified-Since,而且返回的响应中,状态变为了304,这是怎么回事?还记得红薯那篇文章页中的304么,你会发现,304多出现在对于静态资源的请求上面。
原来对于静态资源来说:

  1. 当浏览器第一次发起请求时(请求头中没有If-Modified-Since),server会在响应中告诉浏览器这个资源最后修改的时间(响应头中的Last-Modified)。(见图1.3)
  2. 浏览器也很聪明,当你再次(点击链接,或者F5,或者回车,但是不能是ctrl+F5)请求这个资源时,浏览器会询问server这个资源自上次告诉我的最后修改时间以来有没有被修改(请求头中If-Modified-Since)。(见图1.4)
  3. 如果资源没有被修改,server返回304状态码,并不会再次将资源发送给浏览器,浏览器则很知趣的使用本地的缓存文件。(见图1.4)
    所以所有的静态资源如果没有发生变化,通常是不会传递多次的,不管什么浏览器或者server都应该遵守这种询问的约定。看起来很爽啊,很智能是不是?这种约定的机制就是 Http缓存协商——这是约定优于配置的又一体现。

有了缓存协商的知识,理解为什么我们不应该重写service就很容易了。还是从代码出发,这次我们看一个复杂一点的例子:
在这个例子中,我们请求一个控制器(MeServlet),然后转向一个视图(index.html),为了简单起见,web.xml中将只有这个servlet的配置:

<web-app> 
    <servlet> 
        <servlet-name>me</servlet-name> 
        <servlet-class>com.me.web.MeServlet</servlet-class> 
    </servlet> 
    <servlet-mapping> 
        <servlet-name>me</servlet-name> 
        <url-pattern>/test</url-pattern> 
    </servlet-mapping> 
</web-app>

然后是MeServlet:

public class MeServlet extends HttpServlet { 
    @Override 
    protected void service(HttpServletRequest req, HttpServletResponse res) 
            throws ServletException, IOException { 
        /** 
         * 1. 处理具体的业务: 
         * -- 处理请求参数 
         * -- 检查缓存 
         * -- 处理具体数据 
         * -- 更新缓存 
         */ 
        doBizLogic(req, res); 
        /** 
         * 2. 根据处理的结果转向具体的视图: 
         * -- 这里假设就是 index.html 
         */ 
        getServletContext() 
                .getRequestDispatcher("/index.html").include(req, res); 
    } 
    public void doBizLogic(HttpServletRequest request, HttpServletResponse response) { 
        System.out.println("do biz."); 
    } 
}

可以看到,每次F5刷新返回的状态码都是200,让我们看看具体的请求和响应头:
在这里插入图片描述

我们发现无论我们如何刷新页面,每次响应状态都是200,index.html的内容每次都被完整的发送给浏览器,这看起来很笨,为什么不像静态资源一样进行缓存协商呢?
原因是缓存协商是基于http请求和响应头中的Modified信息的,如果没有这个信息,是无法进行缓存协商的。而对于动态内容而言,server无法帮我们决定内容是不是有改变,也无法替我们决定动态内容的最后修改时间。
所以它不会帮我们在响应中加上Last-Modified,我们必须自己来做这件事,我们小小地修改一下MeServlet:

public class MeServlet extends HttpServlet { 
    @Override 
    protected long getLastModified(HttpServletRequest req) { 
        /** 
         * 这里你要自己决定动态内容的最后修改时间,例如你可以返回 
         * -- 数据缓存最后更新的时间 
         * -- 简单起见,我们假设最后的修改时间是 1000 
         */ 
        return 1000; 
    } 
    @Override 
    protected void service(HttpServletRequest req, HttpServletResponse res) 
            throws ServletException, IOException { 
        /** 
         * 1. 处理具体的业务: 
         * -- 处理请求参数 
         * -- 检查缓存 
         * -- 处理具体数据 
         * -- 更新缓存 
         */ 
        doBizLogic(req, res); 
        /** 
         * 2. 根据处理的结果转向具体的视图: 
         * -- 这里假设就是 index.html 
         */ 
        getServletContext() 
                .getRequestDispatcher("/index.html").include(req, res); 
    } 
    public void doBizLogic(HttpServletRequest request, HttpServletResponse response) { 
        System.out.println("do biz."); 
    } 
}

你会看到getLastModified这个方法是重写的,说明HttpServlet中已经有了这个方法,我们使用这个方法来告诉server在这个动态资源中,最后内容变化的时间是多少。最理想的情况是server会自己回调这个方法,那就太省心啦。
我们先访问的看看:发现依然每次都是200,server没有告诉浏览器最后的修改时间,缓存协商机制无法工作。
先别沮丧,忘了我们要解释什么问题吗——为什么不要重写service方法。也许你已经猜到了,如果你看看service方法的实现,现在你已经明白了,service方法自己实现了缓存协商的机制,如果我们重写它,反而将这中良好的机制给去掉了。
在这里插入图片描述
我们再修改一下,这次我们重写doGet,在doGet中完成完全相同的逻辑:

public class MeServlet extends HttpServlet { 
    @Override 
    protected long getLastModified(HttpServletRequest req) { 
        /** 
         * 这里你要自己决定动态内容的最后修改时间,例如你可以返回 
         * -- 数据缓存最后更新的时间 
         * -- 简单起见,我们假设最后的修改时间是 1000 
         */ 
        return 1000; 
    } 
    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse res) 
            throws ServletException, IOException { 
        /** 
         * 1. 处理具体的业务: 
         * -- 处理请求参数 
         * -- 检查缓存 
         * -- 处理具体数据 
         * -- 更新缓存 
         */ 
        doBizLogic(req, res); 
        /** 
         * 2. 根据处理的结果转向具体的视图: 
         * -- 这里假设就是 index.html 
         */ 
        getServletContext() 
                .getRequestDispatcher("/index.html").include(req, res); 
    } 
    public void doBizLogic(HttpServletRequest request, HttpServletResponse response) { 
        System.out.println("do biz."); 
    } 
}

这次再访问:
在这里插入图片描述
终于出现了久违的Last-Modified,再次回车请求页面,变成304了。
在这里插入图片描述
现在你也许已经清楚了,为什么不应该重写service方法,似乎是为了保留HttpServlet默认实现的缓存协商的机制;其实还有另外一个原因:就是禁用你没有在servlet中重写的方法,例如post、head等,这样就从一定程度上提高了安全性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值