前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >为什么不应该重写 service 方法?

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

作者头像
芋道源码
发布于 2019-09-25 02:04:08
发布于 2019-09-25 02:04:08
42000
代码可运行
举报
文章被收录于专栏:芋道源码1024芋道源码1024
运行总次数:0
代码可运行

来源:http://rrd.me/esQEx

故事通常是这样开始的: 从前,有一个程序猿,他语重心长地对孙子说:“孩子,要是你以后写servlet,最好不要重写service方法啊” 孙子大为不解,程序猿又说:“听爷爷的,准没错,爷爷的爷爷就是这么说的……”

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

如果你也曾思考过这个问题,但暂时无解,这篇文章或许可以给你一点启发。

先来看一个具体的例子:

当时我正在osc看红薯的一篇大作,只见我右手F12熟练的打开了chrome的开发者工具,左手迅猛的按了几下F5,然后看到了这个结果。

聪明的你一定已经发现,除了第一个名为12_77118的请求返回状态为200,其他的都为304,那么200和304有什么区别呢?这个稍后解释。

一切从代码里面来,我们先抛开理论,看一个具体的code:

我编写了一个index.html,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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>

我们来访问这个页面看看。

Image(2)

这是我第一次访问这个页面(表示本地并没有对这个文件的缓存):

我们来看看http请求和响应的消息头:

《图:一》

为了作为对比,我们再F5刷新一次:

《图:二》

这次请求的头信息中多了一条If-Modified-Since,而且返回的响应中,状态变为了304,这是怎么回事?还记得红薯那篇文章页中的304么,你会发现,304多出现在对于静态资源的请求上面。

原来对于静态资源来说:

  1. 当浏览器第一次发起请求时(请求头中没有If-Modified-Since),server会在响应中告诉浏览器这个资源最后修改的时间(响应头中的Last-Modified)。(见图一)
  2. 浏览器也很聪明,当你再次(点击链接,或者F5,或者回车,但是不能是ctrl+F5)请求这个资源时,浏览器会询问server这个资源自上次告诉我的最后修改时间以来有没有被修改(请求头中If-Modified-Since)。(见图二)
  3. 如果资源没有被修改,server返回304状态码,并不会再次将资源发送给浏览器,浏览器则很知趣的使用本地的缓存文件。(见图二)

所以所有的静态资源如果没有发生变化,通常是不会传递多次的,不管什么浏览器或者server都应该遵守这种询问的约定。看起来很爽啊,很智能是不是?这种约定的机制就是 http缓存协商——这是约定优于配置的又一体现。

有了缓存协商的知识,理解为什么我们不应该重写service就很容易了。还是从代码出发,这次我们看一个复杂一点的例子:

在这个例子中,我们请求一个控制器(MeServlet),然后转向一个视图(index.html),为了简单起见,web.xml中将只有这个servlet的配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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中完成完全相同的逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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等,这样就从一定程度上提高了安全性。

理论到此为止,现在让我们来看看缓存协商机制有什么实际的好处:

还是红薯的那边文章,我们现在全加载(ctrl+F5)一次看看,

我们看到总共发起了45个请求,请求的数据量为198.93KB,然后F5刷新一次:

这次只有36个请求,数据量只有23.62KB

我们看到这篇文章被9960个id访问, 而每一个id实际上可能访问这个页面多次(像我这样,实际的数据可能得问问红薯),然后我们看到很多304静态资源都是整站通用的:

如果你是osc的常客,并且不经常更换浏览器,不经常清理缓存,甚至其他人的头像都可以是通用的,为了简单起见,我们这里考虑每个id都只访问这个页面一次,并且假设所有的资源都已经缓存在用户本地,得出:

(198.93-23.62)×9960 = 1746086.6KB = 1705.1637M = 1.665G。

很惊人吧,这只是一个页面,别忘了,我们还假设所有的用户都只访问一次,你想想osc上面有多少篇博文,加起来……

流量是什么,是银子啊。

幸运的是,这些省银子的事情浏览器和server都已经帮我们做好了,那我们就不需要关心这个了吗??我们看到12_77118这个请求所占用的资源也不少,如果文章再长点,再长点的话……还会更大。

如果红薯愿意,也可以让这个请求实现缓存协商,可以进一步减少流量。

当然这里的计算并不是完全的精确,实际的情况复杂很多,但是这个计算的量级应该是对的,是值得参考的。

流量涉及的另一个问题就是带宽,以更小的贷款提供更高的并发是每个站长应该追求的。不过考虑到osc以新闻为主,一次性消费,所以……不过那时题外话了。

好了,如果你有耐心看到这里,我想你也许会对service有了新的理解,为什么我们不应该重写这个方法。

万事有例外,如果你需要实现一个前端控制器的话,就是另外一回事了,这留给大家自己思考。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芋道源码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
《Indie Tools • 半月刊》第009期
#IndieTools 是一个专为 #独立开发者 打造的精选工具和资源平台。汇聚 #Web开发、#设计、#营销、#SEO 等全流程实用工具
沉浸式趣谈
2025/05/01
370
《Indie Tools • 半月刊》第009期
打破传统思维:关键词采集与市场调查的完美结合,引领你的行业领先
作为一名市场调查人员,我们需要了解目标用户的行为和偏好,以便为相关产品制定更有效的市场策略。在如今互联网时代,利用关键词采集工具是一个非常有效的方式,下面我将从十个方面介绍如何利用关键词采集工具了解目标用户的行为和偏好,并制定相应的市场调查方案。
小胡爱学习
2023/04/05
3480
革新市场营销,突破瓶颈:关键词采集和市场调查的秘密武器
近年来,全球新兴行业不断涌现,其中一些行业甚至成为了热门话题。这些新兴行业的出现,不仅带来了新的商机和发展机遇,也对传统产业带来了冲击和挑战。对于那些想要进入新兴行业的人来说,了解这些行业的关键词和市场情况,是非常重要的。本文将揭秘成功进入全球最热门新兴行业的秘诀:关键词采集和市场调查。
小胡爱学习
2023/04/05
2710
革新市场营销,突破瓶颈:关键词采集和市场调查的秘密武器
突破市场壁垒:如何利用关键词采集和市场调查找到你的细分市场?
在市场竞争日益激烈的今天,寻找一个适合自己的细分市场成为了每个企业和创业者的必要之举。然而,许多人在寻找细分市场时陷入了困境,不知道如何找到一个符合自己产品的市场,因此,在这种情况下,利用关键词采集和市场调查成为了一种非常有效的方法。本文将从关键词采集软件的优势和市场调查两个方面着手,为大家讲解如何通过这两种方法找到自己的细分市场。
小胡爱学习
2023/04/05
3460
突破市场壁垒:如何利用关键词采集和市场调查找到你的细分市场?
​拓客必备神器:采集工具让你的数据采集更快更准
企业拓客是指企业通过各种手段,寻找并获取新客户的过程。对于企业来说,拓客是非常重要的一环,可以帮助企业扩大市场份额、提高销售额、增加利润等。但是,拓客过程中存在着一些难点和挑战,例如如何精准定位目标客户、如何获取有效的联系方式等。在这个过程中,关键词采集工具可以发挥重要的作用。
小胡爱学习
2023/04/07
5450
​拓客必备神器:采集工具让你的数据采集更快更准
MediaCrawler,轻松爬取抖音小红书评论数据!
https://github.com/NanmiCoder/MediaCrawler
小F
2024/04/15
3.4K0
MediaCrawler,轻松爬取抖音小红书评论数据!
如何根据搜索来源进行关键词针对性布局?
关键词优化是指把网站里面的关键词进行选词和排版的优化达到优化网站排名的效果,搜索引擎中相关关键词的排名中占据有利的位置。关键词优化是让网站目标关键词在某个搜索引擎上得到更好的排名,让更多的用户都能快速的查找到自己的网站关键词。
茹莱神兽
2022/02/04
4410
如何根据搜索来源进行关键词针对性布局?
独立开发者工具 • 半月刊 第 008 期
IndieTools 是一个专为独立开发者打造的精选工具和资源平台。汇聚 Web 开发、设计、营销、SEO 等全流程实用工具。
沉浸式趣谈
2025/04/30
860
教你几招,轻松学会品牌知名度衡量的基本方法!
通过衡量品牌知名度来划分市场。有些人认为这是一项毫无意义的工作,是一个与营销ROI无关的虚荣指标。
iCDO互联网数据官
2018/07/26
3.8K0
教你几招,轻松学会品牌知名度衡量的基本方法!
数据驱动运营?试试这款开源工具做可视化分析!
在当今快速变化的市场环境中,运营面临着许多挑战,这些挑战直接影响到企业的生存与发展
至存网络
2024/08/26
1900
数据驱动运营?试试这款开源工具做可视化分析!
Python爬虫实战:揭秘汽车行业的数据宝藏与商业机会
随着数字化时代的到来,数据已经成为推动企业成功的重要资源。而在当今快速发展的汽车行业中,数据更是隐藏着巨大的商业潜力。本文将带您进入Python爬虫的实战领域,教您如何抓取和分析汽车行业数据,探索其中的操作价值和含金量,为您的汽车业务带来竞争优势。
用户614136809
2023/09/12
4160
SEO小贴士:网站内容营销,你如何理解!
作为一个成熟的互联网企业,基于网站优化的内容营销,蝙蝠侠IT,在以往的工作经历中,会先定义:网站内容营销的目的,从而在进一步制定相关策略。
蝙蝠侠IT
2019/07/11
5690
SEO小贴士:网站内容营销,你如何理解!
【工具介绍】四种调研工具赋能内容营销!
引言:充分的前期调研是制定成功的内容营销策略的关键。以下介绍四种调研工具,助你显著提升内容营销策略。
iCDO互联网数据官
2018/11/30
1.3K0
【工具介绍】四种调研工具赋能内容营销!
《INDIE TOOLS • 半月刊》第003期
5118.com 是一款专注于关键词挖掘和分析的工具,帮助用户优化SEO和内容策略。
沉浸式趣谈
2025/02/04
560
《INDIE TOOLS • 半月刊》第003期
数据分析:挖掘竞争对手和行业的广告投放方法和竞争策略
可能很多人随口都能说上几种,这也确实是数据的魅力和能力,这里不讲大家耳熟能详的,这次就讲讲数据在SEM营销推广中分析和认知竞争对手的内容:竞争对手都是怎么投放广告的,他到底是怎么进行推广的,他的主要诉求是什么?
沉默的白面书生
2018/08/15
1.4K0
数据分析:挖掘竞争对手和行业的广告投放方法和竞争策略
搜索引擎关键词采集,联系任务采集,网址采集
使用搜索引擎进行关键词的采集,可以让我们获得更多的信息并准确地找到我们所需要的内容。通过使用搜索引擎,我们可以快速搜索全球各地的网页、文章、资料以及其他文档。除此之外,搜索引擎还提供与主题相关的相关性排序,这样可以更快速有效地了解当前所要访问的内容。
小胡爱学习
2023/04/04
8760
搜索引擎关键词采集,联系任务采集,网址采集
产品运营是做什么的?新手运营必读篇
产品运营是产品取得成功,实现产品的商业目标的重要支撑。产品运营岗位的专业能力要求庞杂,在岗或准备入坑人员应该如何巩固自身的知识/技能树?
奔跑的小鹿
2023/11/03
1.4K0
产品运营是做什么的?新手运营必读篇
科特勒中国区管理合伙人王赛:数据是企业生存发展的核心壁垒
随着科技的迅猛发展,数智化浪潮正席卷全球各个行业,市场营销也不例外。在信息时代,数据成为了企业的宝贵资产,而智能科技的崛起为市场营销注入了新的活力和可能性。然而,数智浪潮下,市场营销有了更多的变化,智能科技将如何引领商业新风向?
数据猿
2023/12/11
2320
科特勒中国区管理合伙人王赛:数据是企业生存发展的核心壁垒
驾驭AI为品牌服务,从成为卓越投喂师开始!
在这个信息爆炸、注意力稀缺的时代,品牌内容营销已成为企业连接消费者、塑造品牌形象的关键途径。而人工智能(AI)技术的融入,更是为内容营销带来了前所未有的变革与机遇。然而,要让AI真正为你的品牌内容营销高效服务,你首先需要成为一位卓越的“投喂师”。这不仅仅是对技术的简单应用,更是对内容策略、用户洞察与数据优化的深度整合。本文将为你揭示如何成为这样的投喂师,让AI成为你品牌内容营销的强大助力。
内容营销专家刘鑫炜
2024/09/07
870
采集线下零售消费评价数据,指导商业地产运营
疫情放开后的2023年,人们的生活和工作逐步回到原本熟悉的轨道上。街上的车开始拥堵,城市商圈也逐渐回暖,有观点认为:2023年商业地产将迎来“转折之年”。
用户10840786
2023/12/06
3360
采集线下零售消费评价数据,指导商业地产运营
推荐阅读
相关推荐
《Indie Tools • 半月刊》第009期
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验