最佳实践分享:优化阿里云HTTPS申请与使用效果

一、引言

随着互联网技术的飞速发展,HTTPS协议已经成为网站安全的重要保障。
阿里云作为国内领先的云服务提供商,其HTTPS服务广泛应用于各类网站和企业应用中。
本文将介绍什么是最佳实践,以及在申请和使用阿里云HTTPS服务过程中,如何进行优化,以获得更好的效果。

二、最佳实践概述

最佳实践是指在特定领域或情境中,经过实践证明最为有效、最具有操作性的方法和经验。
在云计算和网络安全领域,最佳实践对于提高服务效率、降低成本、保障安全等方面具有重要意义。
本文将以阿里云HTTPS服务为例,分享一些最佳实践,帮助用户优化申请与使用过程。

三、优化阿里云HTTPS申请

1. 提前准备资料:在申请阿里云HTTPS证书之前,提前准备好所需的资料,如域名、企业资质等。确保资料准确无误,可以加快审核速度。
2. 选择合适的证书类型:阿里云提供多种HTTPS证书类型,包括免费DV证书、付费DV证书和EV证书等。根据实际需求选择合适的证书类型,以满足安全性和预算要求。
3. 批量管理证书:如果需要在阿里云上管理多个域名或证书,可以使用批量管理功能,提高管理效率。
4. 关注优惠活动:阿里云经常推出关于HTTPS证书的优惠活动,关注官方活动信息,可以节省成本。

四、优化阿里云HTTPS使用效果

1. 配置优化:在使用阿里云HTTPS服务时,合理配置服务器参数,如选择正确的加密套件、调整缓存策略等,以提高网站访问速度和安全性。
2. 监控与报警:启用阿里云的安全监控服务,对HTTPS服务进行实时监控。一旦出现异常,及时报警并处理,确保网站安全稳定运行。
3. 定期更新与维护:定期更新HTTPS证书,确保证书始终处于有效状态。同时,对服务器进行定期维护,以提高性能和安全。
4. 使用CDN加速:结合阿里云的内容分发网络(CDN)服务,对HTTPS内容进行加速,提高用户访问体验。
5. 用户体验优化:优化网站设计,提高页面加载速度,减少HTTP到HTTPS的跳转延迟,提高用户体验。
6. 安全教育培训:加强员工对网络安全的认识,定期进行安全教育培训,提高整个团队的安全意识和应对能力。

五、案例分析

以某电商网站为例,该网站在使用阿里云HTTPS服务后,通过优化申请和使用过程,取得了显著的效果。
提前准备好申请资料,选择了合适的证书类型,加快了证书申请和审核速度。
在使用过程中,合理配置服务器参数,启用安全监控服务,定期更新和维护证书。
结合CDN加速和用户体验优化,提高了网站访问速度和用户满意度。
通过安全教育培训,提高了整个团队的安全意识和应对能力。
这些优化措施使得该电商网站在保障安全的同时,也取得了良好的业务增长。

六、结论

本文介绍了最佳实践的概念,以及在申请和使用阿里云HTTPS服务过程中,如何进行优化。
通过提前准备资料、选择合适的证书类型、批量管理证书、关注优惠活动、配置优化、监控与报警、定期更新与维护、使用CDN加速、用户体验优化以及安全教育培训等措施,可以提高阿里云HTTPS服务的申请和使用效果。
希望本文的最佳实践分享能对广大阿里云用户有所帮助。


流程优化、流程重组、流程再造如何实现价值

流程是否真的都管起来了?当初进行流程优化的目的是否都已经达成了?流程管理是否真正的实现了他的价值? 流程的重要性怎么说都不为过,但流程要怎样落地?AMT咨询有三层的战略执行保障体系,第一层是战略执行系列,然后是流程价值系列,最后是IT支撑系列,这三层保障企业战略的执行。 本文将着重阐述流程是怎样保证我们的战略落地的,即战略要真正落地,该怎么样体现在流程上。 流程手段,落实战略执行的关键 大部分企业都制定了宏伟的战略和目标,但只有将这些战略和目标真正落实在流程上面,才是真正开始执行战略。 企业通常做了总的战略部署之后还要做分领域的业务战略,细分到市场、研发、生产,一直分解到具体的活动。 所以,战略只有落实到具体运转的活动中才是进入了执行的阶段。 也只有在执行的阶段,你才会发现,整个企业的战略举措及目标的价值,其实就是在一层层流程运转过程中创造的。 在某一个领域做采购想要节约成本,可能会有一个跨部门的流程,比如新产品上市;可能还有一些跨岗位的,比如供应商的管理。 在这里面我们很清楚地看到,不管目标有多么宏伟,多么远大,都是靠流程一点一滴运转起来的。 而且不仅靠流程,还要靠结构,只有这样才能保证目标价值的最大化。 GE的前CEO杰克·威尔奇做流程再造,把企业24层变成了7层;ABB创造的矩阵式管理,打造了真正国际化的企业,因为当时很多的国际公司跟中国公司一样有国际部,当时做了一个面向全球的矩阵式的企业。 他们两个流程再造就打造了一个流程再造的时代,现在我们很少听到他们说流程再造了,因为这已经变成了日常工作。 而中国企业做流程再造还是值得宣传的东西,比如海尔花了五年打造市场价值链,海尔创业十九年中最核心的就是BPR与市场链这五年,他们重点切入,逐步建立了客户需求核心体系。 很多企业都希望是客户导向企业,但其实并没那么容易。 破解流程优化几大迷团 流程有这么大的价值,对执行有着这么重要的作用,因此大家都争相做这件事情。 但在90年代早期进行的一系列调查显示,超过一半的业务流程重组项目走向失败或是达不到最初设定的目标。 基于这种情况,我们要找一找流程有哪些地方做的不对,成功的要点有哪些。 首先要明确对流程的理解。 说流程很重要,但只是表述企业业务和管理的一种语言。 流程的好处是可以用一个流程模型表述整个企业的业务模式,表述某一业务领域的业务模式,然后下面形成一级流程、二级流程,这些流程表述的是业务的运转,最底层的流程,一定要形成手册和表单。 手册和表单表示业务的标准化、知识化。 倒过来我们会看到做流程优化的时候有三个层次的优化,第一个是对整个企业业务模式的优化,就是流程框架体系的优化;第二个,业务的优化,就是流程的优化;第三个手册、表单的优化。 当然不能忘掉贯穿一个公司所有流程始终的就是IT系统的支撑,什么样的企业是最成功的,就是能够把企业战略放在IT里面的企业。 流程的几个方面落实到企业的实际层面会有几大谜团。 如BPR失败之迷、关键流程优化失败之迷、流程持续改进之迷、流程复制之迷、流程与IT融合之迷等等。 也就是说我们发现有很多关键流程的优化,实际的效果并不是太明显;还有很多的企业把流程都梳理了,最后这些流程都变成了手册,变成了文件柜里面很重要的文件,过了一年发现这些文件已经没用了,无法持续改进;再有就是中国的企业已经发展到海外,有些控制不住了。 什么叫控制不住?就是突然发现我们在国内的流程不可以复制到国外,不能很好地管理企业。 BPR失败之迷 讲到BPR——业务流程重组,一般对业务流程重组有哪些初始希望呢?建立一个客户导向的组织;实现横向部门之间、岗位之间的顺畅沟通;实现对业务的管控落地,而又不影响对市场的快速响应;实现业务运转过程中关键点的控制,解决流程烦琐的问题、流转成本高的问题……,这么多希望都要规范化、标准化,这样一来企业就痛苦了,就会影响业务,影响生存。 ◆首先要回归对业务流程重组的核心定位。 业务流程真正的作用是帮助企业搭建一个运营的平台,而且是可落地的可运营的平台,使企业的整体架构是一个完美的架构,一个良好的架构。 也就是杰克·威尔奇说过的持续可积累的架构,ABB也有这个口号,这个是我们首先要想清楚的。 ◆要走出传统做法的误区。 实际上定位企业架构的时候,我们常常采用传统的做法,一般经历前期管理诊断、建立集团管理框架、组织设计、关键流程优化及关键制度完善、绩效考核体系设计的过程。 流程讲究放权,强调组织机构设计,信奉流程决定组织,组织决定完了才做流程,认为增值的流程才是关键流程,所有管理流程都是不增值的,它存在的理由就是保证整体和某一个领域的价值最大化,最后搞绩效。 这些传统的做法有两大误区:首先,没有关注业务流程的本质,产生的根源是因为竞争的时代,我们要以客户为导向。 其次,简单的管控模式不能解决业务问题,不同业务运转背后的模式是不一样的,而且它没有真正解决流程衔接的问题。 ◆ 既要关注客户导向价值传递,还得关注不同业务本身,借鉴最佳实践的优化。 我们发现前端有很多的东西要做,对市场细分,细分出哪些客户群,不一样的客户群我们要配什么样的产品,比如要生产大批电脑,因为客户群不一样,生产的策略也就不一样。 不同的策略对应的关键活动是不一样的,流程是不一样的,然后你会发现不同的关键控制点不一样。 这些控制点,假如说你放在某一个领域,对某一个管控品进行管控,这就上升到集团管控层面,要注意这个管控是不是可以落地、可操作的、可以执行的。 举例来说,第一个流程要以客户导向传递;第二个就要研究不同业务领域的特点。 要看到业务不同的特点,发现不同的业务领域其实有很多的最佳实践,关键的是怎样让这些最佳实践落到企业上,变成企业真正可操作的业务模式。 在分析的基础上,我们会发现企业采购模式一些是集中采购,还有一些是分散采购,甚至这些采购还会影响到生产成本。 这时我们要搭建经营平台,除了以客户为导向,还要对各个指标进行分析。 这样才能让企业的运作成本更低,效率更高。 这就是既管控又要落地,又不影响对市场快速响应。 ◆ 不能“一步实现,全面开花”,这样会影响业务运营与发展,最终使BPR项目流产。 一个供应商采购,可能后面还有很多的最佳实践,还有成本模型的问题,合作伙伴协作的问题,真要分析起来是很复杂的。 你要搭建一个很好的体系,不是想一步到位就能一步到位的,一步到位的结果最后都是失败的。 所以我们一定要找到企业所能承受目标和范围,对整个过程进行变革管理。 关键流程优化失败之迷 关键流程的选择其实很不容易。 比如一个采购流程,几乎涉及到企业的所有部门,所有业务关系。 会发现关键流程分解下来还会有很多层,关键流程背后会有很多表单要优化,可能还会发现不做考核,流程是没法推行的,所以考核和绩效指标都是配套的。 最后发现要让公司的每个人都按照这个来做,还要做很多工作。 这里有很多工作要做,如果我们简单选择关键流程,那么企业会有很多流程选出来是劳而无功的。 回归到关键流程的本质,整个结果可能是业务模式产生变动,所以关键流程优化,问题导向是关键。 要能够识别关键问题,进行关键问题流程分析,发现并总结问题根源,最终提出解决的思路。 流程复制之迷 为什么企业建立了流程体系,但是新建立子公司,又要重新梳理?为什么国际性的大公司能够迅速复制工作方式到新的子公司? ◆ 流程的复制,最关键就是IT固化。 也就是让流程标准化,规范化,用统一的术语说清事情,规范运作。 让大家统一去做,肯定是聪明人不愿意,笨的人不会做,我们要找一个比聪明人还要好的流程,形成最佳实践,这个最佳实践要变成知识,只要把这些东西变成知识,就把过程的能力变成整个企业的能力。 ◆ 流程的复制,除了IT固化以外,还要做好科学、标准的流程手册。 流程手册不仅仅记录流程是如何操作的,还记载了:流程中每个活动的考虑因素是什么?有什么判断经验?判断的量化指标值是什么?注意事项是什么?把个人的知识转变为企业的知识,把个人的能力转变为企业的能力。 流程与IT融合之谜 某组织机构对IT类项目实施结果的统计数据显示:16.2%的项目实现其目标,即按时,在预算范围内,满足最初的项目要求;52.7%的项目需要补救,即超预算,超时间,未全面满足最初的项目要求;31.1%的项目失败,即在项目的某一阶段中止。 IT项目的失败率高达83.8%!为什么IT建设项目失败率这么高?什么是成功,上线并不代表IT项目已经成功,而是要实现管理的目标,真正达到预期的价值,并且是在预算范围之内。 IT系统实施前,必须要梳理流程也就是优化流程,为IT项目打基础。 企业的管控体系怎么样,关键控制点在哪里,这些分析透彻,上IT系统的目标就出来了。 这时候再把流程描述出来,控制点、岗位、表单……,真正做到这种程度,你会发现IT系统上线肯定是成功的。 要做好流程,企业就要因地制宜,采用多种流程管理推进方法——流程重组:客户导向,面向业务模式的流程优化,企业整体优化,是基础工作;流程优化:针对某一特定的目标或问题(如对大客户的响应速度、降低采购成本等),来解决问题,使流程价值落地;流程梳理:规范企业管理,打下企业流程管理的基础

有状态的Web应用程序都有漏洞吗?求答案

在没有足够协作的情况下,许多 Web 应用程序对可变数据(比如 JavaBeans 类)使用了 HttpSession 这个机制,从而使自身面临大量潜在的并发性危险。 虽然Java? 生态系统中存在许多 Web 框架,但它们都直接或间接地基于 Servlets 基础设施。 Servlets API 提供大量有用特性,包括通过 HttpSession 和ServletContext 机制提供的状态管理,它允许应用程序在跨多个用户请求时保持状态。 然而,在 Web 应用程序中使用共享状态受一些微妙的(并且大部分没有进行说明)的规则控制着,因此导致许多应用程序无意中触犯了规则。 结果是许多有状态 Web 应用程序存在难以发觉的严重缺陷。 范围容器在Servlet 规范中,ServletContext、HttpSession 和HttpRequest 对象被称为 范围容器(Scoped container)。 它们都有 getAttribute() 和setAttribute() 方法,为应用程序存储数据。 这些范围容器的区别在于它们的生命周期不同。 对于 HttpRequest,数据只在请求期间有效;对于 HttpSession,数据在用户和应用程序的会话期间有效;而对于 ServletContext,数据在应用程序的整个生命周期中都有效。 由于HTTP 协议是没有状态的,所以范围容器在构造有状态 Web 应用程序时十分有用;servlet 容器负责管理应用程序的状态和数据的生命周期。 尽管这个规范没有强调,但需要保证嵌套在会话或应用程序中的容器在某种程度上是线程安全的,因为 getAttribute() 和setAttribute() 方法随时都可能被不同的线程调用(这个规范没有直接要求这些实现必须是线程安全的,但它们提供的服务实际上提出了这一点)。 范围容器还为 Web 应用程序提供一个潜在的好处:容器可以透明地管理应用程序状态的复制和故障转移。 会话session 是特定用户和 Web 应用程序之间的一系列请求-响应交换。 用户希望 Web 站点记住他的身份验证凭证、购物车的物品,以及在前面的请求中输入到 Web 表单的信息。 但核心 HTTP 协议是没有状态的,这意味着必须将所有请求信息存储到请求本身。 因此,如果要创建比一个请求-响应周期更长的有用交互,就必须存储会话状态。 servlet 框架允许将每个请求与一个会话关联起来,并提供充当值存储库的 HttpSession 接口,用于存储与该会话相关的(键,值)数据项。 清单 1 是一段典型的 servlet 代码,它用于在 HttpSession 中存储购物车数据:清单1. 使用 HttpSession 存储购物车数据 HttpSession session = (true); ShoppingCart cart = (ShoppingCart)(shoppingCart); if (cart == null) { cart = new ShoppingCart(...); (shoppingCart); } doSomethingWith(cart); 清单1 提供的是 servlet 的典型用途;这个应用程序查看是否已将一个对象放到会话中,如果还没有,它将创建一个该会话的后续请求可以使用的对象。 构建在 servlet 之上的 Web 框架(比如 JSP、JSF 和 SpringMVC 等)隐藏了细节情况,但对于标记为嵌入到会话中的数据,它们替您执行了实际操作。 不幸的是,清单 1 中的用法很可能是不正确的。 与线程相关的问题当HTTP 请求到达 servlet 容器之后,会在 servlet 容器管理的线程上下文中创建 HttpRequest 和HttpResponse 对象,并传递给 servlet 的 service() 方法。 servlet 负责生成响应;在响应完成之前 servlet 一直控制这个线程,响应完成时该线程返回到可用的线程池。 Servlet 容器没有保持线程与会话之间的联系;某个会话的下一个请求很可能由另一个不同的线程来处理。 事实上,可能有多个请求同时进入同一个会话(当用户与页面交互时,使用框架或 AJAX 技术从服务器获取数据的 Web 应用程序可能发生这种现象)。 在这种情况,同一用户可能发出多个请求,这些请求在不同的线程上并行执行。 大多数情况下,这类线程问题与 Web 应用程序开发人员无关。 由于自身没有状态,HTTP 鼓励只有存储在请求中的数据(不与其他并发请求共享)和存储在存储库(比如数据库)中的、已进行并发 ...展开在没有足够协作的情况下,许多 Web 应用程序对可变数据(比如 JavaBeans 类)使用了 HttpSession 这个机制,从而使自身面临大量潜在的并发性危险。 虽然Java? 生态系统中存在许多 Web 框架,但它们都直接或间接地基于 Servlets 基础设施。 Servlets API 提供大量有用特性,包括通过 HttpSession 和ServletContext 机制提供的状态管理,它允许应用程序在跨多个用户请求时保持状态。 然而,在 Web 应用程序中使用共享状态受一些微妙的(并且大部分没有进行说明)的规则控制着,因此导致许多应用程序无意中触犯了规则。 结果是许多有状态 Web 应用程序存在难以发觉的严重缺陷。 范围容器在Servlet 规范中,ServletContext、HttpSession 和HttpRequest 对象被称为 范围容器(Scoped container)。 它们都有 getAttribute() 和setAttribute() 方法,为应用程序存储数据。 这些范围容器的区别在于它们的生命周期不同。 对于 HttpRequest,数据只在请求期间有效;对于 HttpSession,数据在用户和应用程序的会话期间有效;而对于 ServletContext,数据在应用程序的整个生命周期中都有效。 由于HTTP 协议是没有状态的,所以范围容器在构造有状态 Web 应用程序时十分有用;servlet 容器负责管理应用程序的状态和数据的生命周期。 尽管这个规范没有强调,但需要保证嵌套在会话或应用程序中的容器在某种程度上是线程安全的,因为 getAttribute() 和setAttribute() 方法随时都可能被不同的线程调用(这个规范没有直接要求这些实现必须是线程安全的,但它们提供的服务实际上提出了这一点)。 范围容器还为 Web 应用程序提供一个潜在的好处:容器可以透明地管理应用程序状态的复制和故障转移。 会话session 是特定用户和 Web 应用程序之间的一系列请求-响应交换。 用户希望 Web 站点记住他的身份验证凭证、购物车的物品,以及在前面的请求中输入到 Web 表单的信息。 但核心 HTTP 协议是没有状态的,这意味着必须将所有请求信息存储到请求本身。 因此,如果要创建比一个请求-响应周期更长的有用交互,就必须存储会话状态。 servlet 框架允许将每个请求与一个会话关联起来,并提供充当值存储库的 HttpSession 接口,用于存储与该会话相关的(键,值)数据项。 清单 1 是一段典型的 servlet 代码,它用于在 HttpSession 中存储购物车数据:清单1. 使用 HttpSession 存储购物车数据 HttpSession session = (true); ShoppingCart cart = (ShoppingCart)(shoppingCart); if (cart == null) { cart = new ShoppingCart(...); (shoppingCart); } doSomethingWith(cart); 清单1 提供的是 servlet 的典型用途;这个应用程序查看是否已将一个对象放到会话中,如果还没有,它将创建一个该会话的后续请求可以使用的对象。 构建在 servlet 之上的 Web 框架(比如 JSP、JSF 和 SpringMVC 等)隐藏了细节情况,但对于标记为嵌入到会话中的数据,它们替您执行了实际操作。 不幸的是,清单 1 中的用法很可能是不正确的。 与线程相关的问题当HTTP 请求到达 servlet 容器之后,会在 servlet 容器管理的线程上下文中创建 HttpRequest 和HttpResponse 对象,并传递给 servlet 的 service() 方法。 servlet 负责生成响应;在响应完成之前 servlet 一直控制这个线程,响应完成时该线程返回到可用的线程池。 Servlet 容器没有保持线程与会话之间的联系;某个会话的下一个请求很可能由另一个不同的线程来处理。 事实上,可能有多个请求同时进入同一个会话(当用户与页面交互时,使用框架或 AJAX 技术从服务器获取数据的 Web 应用程序可能发生这种现象)。 在这种情况,同一用户可能发出多个请求,这些请求在不同的线程上并行执行。 大多数情况下,这类线程问题与 Web 应用程序开发人员无关。 由于自身没有状态,HTTP 鼓励只有存储在请求中的数据(不与其他并发请求共享)和存储在存储库(比如数据库)中的、已进行并发性控制的数据,才具有响应功能。 然而,一旦 Web 应用程序将数据存储在 HttpSession 或ServletContext 等共享容器之后,该 Web 应用程序就具有了并发性,因此必须考虑应用程序内部的线程安全问题。 尽管我们常用线程安全描述代码,但实际上它是描述数据的。 具体来说,线程安全是指适当地协调对被多个线程访问的可变数据的访问。 Servlet 应用程序通常是线程安全的,因为它们没有共享任何可变数据,因此就不需要额外的同步。 但可以通过很多种办法将共享状态引入到 Web 应用程序 — 除了 HttpSession 和ServletContext 等范围容器外,还可以使用 HttpServlet 对象的静态字段和实例字段。 如果要让 Web 应用程序跨请求共享数据,开发人员就必须注意共享数据的位置,并保证访问共享数据时线程之间有足够的协作(同步),以避免与线程相关的危险。 Web 应用程序的线程风险如果Web 应用程序将购物车等可变会话数据存储在 HttpSession 中,就有可能出现两个请求试图同时访问该购物车。 这可能导致以下几种故障: 原子性故障。 在数据不一致的状态下,一个线程正在更新多个数据项,而另一个线程正在读取这些数据 读线程和写线程之间的可见性故障。 一个线程修改购物车,但另一个线程看到的购物车内容的状态是过时的或不一致的 原子性故障清单2 展示了一个用于在游戏应用程序中设置和获取最高分的不恰当的方法实现。 它使用一个 PlayerScore 对象来表示最高分,这实际上是一个具有 name 和score 属性的普通 JavaBean 类,存储在内嵌于应用程序的 ServletContext 中(假设在应用程序启动时,初始最高分在 ServletContext 中被设置为 highScore 属性,因此 getAttribute() 调用不会失败)。 清单2. 在范围容器中存储相关项的不恰当模式 public PlayerScore getHighScore() { ServletContext ctx = getServletConfig()(); PlayerScore hs = (PlayerScore) (highScore); PlayerScore result = new PlayerScore(); (()); (()); return result; } public void updateHighScore(PlayerScore newScore) { ServletContext ctx = getServletConfig()(); PlayerScore hs = (PlayerScore) (highScore); if (() > ()) { (()); (()); } } 清单2 中的代码不够好。 这里采用的方法是在 ServletContext 中存储一个包含最高分玩家的名字和分数的可变容器。 当打破记录时,必须更新名字和分数。 假如当前的最高分玩家是 Bob,他的分数为 1000,但是 Joe 以 1100 分打破了这个记录。 在正要设置 Joe 的分数时,另一个玩家又发出获得最高分的请求。 getHighScore() 将从servlet 上下文获取 PlayerScore 对象,然后从该对象获取名字和分数。 如果不慎出现计时失误,就有可能获取 Bob 的名字和 Joe 的分数,显示 Bob 取得了 1100 分,而实际上 Bob 并没有获得这个分数(这种故障在免费游戏站点上是可以接受的,因为 “分数” 并不是 “银行存款”)。 这是一种原子性故障,因为彼此之间本应该是原子关系的两个操作 — 获取名字/分数对和更新名字/分数对 — 实际上并没有按照原子关系执行,而且其中一个线程可以在不一致状态下查看共享数据。 另外,由于分数更新逻辑遵循 check-then-act 模式,因此可能出现两个线程 “争夺” 更新最高分,从而导致难以预料的结果。 假设当前的最高分是 1000,有两个玩家同时注册更高的分数 1100 和 1200。 如果出现计时失误,这两个分数都能够通过 “高于现有分数的最高分” 检查,并且都进入到更新最高分的代码块中。 和前面一样,根据计时的实际情况,最后的结果可能不一致(采用一个玩家的名字和另一个玩家的分数),或者出现错误(分数为 1100 的玩家可能覆盖分数为 1200 的玩家)。 可见性故障 比原子性故障更复杂的是可见性 故障。 没有同步时,如果一个线程读取另外一个线程正在写的变量,读的线程将看到过时的 数据。 更糟糕的是,读线程还可能会看到 x 变量的最新数据和 y 变量的过时数据,即使先写 y 变量也是这样。 可见性故障非常复杂,因为它的发生是随机的,甚至是频繁的,这会导致罕见的难以调试的间发性故障。 可见性故障是由数据争夺引起的 — 访问共享变量时不能正确同步。 争夺数据的程序,不管它是什么样的,都属于有漏洞的程序,因为它们的行为不能可靠预测。 Java Memory Model(JMM)定义一些条件,它们保证读变量的线程能够看到另一个线程的写入结果(详细讲解 JMM 超出了本文的范围;参见 参考资料)。 JMM 在一个称为 happens-before 的程序的操作上定义一个排序。 只有在通用锁上执行同步或访问一个通用的可变变量时,才能创建跨线程的 Happens-before 排序。 在没有 happens-before 排序的情况下, Java 平台可以延迟或更改顺序,按照这个顺序,一个线程的写操作对于另一个读取同一变量的线程是可见的。 清单2 中的代码不仅有原子性故障,还有可见性故障。 updateHighScore() 方法从 ServletContext 获取HighScore 对象,然后修改它的状态。 这样做的目的是让其他调用 getHighScore() 的线程看见这些修改,但是如果 updateHighScore() 的name 和 score 属性的写操作和其他调用 getHighScore() 的线程的 name 和 score 属性的读操作之间没有 happens-before 排序,我们只能期盼运气好些,让读线程能够看到正确的值。 可能的解决方案尽管servlet 规范没有充分地描述 servlet 容器必须提供的 happens-before 保证,但可以得出结论:将一个属性放置在共享范围容器(HttpSession 或ServletContext)应该在另一个线程获取该属性之前发生。 (参见 JCiP 4.5.1 了解这个结论的推理过程。 该规范中这样描述:“执行请求线程的多个 servlets 可能同时积极地访问单个会话对象。 开发人员负责恰当地同步对会话资源的访问)。 set-after-write 技巧更新存储在其他会话容器中的可变数据时,必须在修改该数据后再次调用 setAttribute()。 这是一种常用的最佳实践。 清单 3 展示了重写 updateHighScore() 以使用这个技巧的示例(这个技巧的目的之一是提示容器值已经更改,因此可以在分布式 Web 应用程序的各个实例之间重新同步会话和应用程序状态)。 清单3. 使用 set-after-write 技巧提示 servlet 容器值已经更新 public void updateHighScore(PlayerScore newScore) { ServletContext ctx = getServletConfig()(); PlayerScore hs = (PlayerScore) (highScore); if (() > ()) { (()); (()); (highScore, hs); } } 不幸的是,尽管这个技巧能够在集群应用程序中高效地复制会话和应用程序状态,但它不能解决本例中的基本线程安全问题。 它可以减轻可见性问题(即另一个玩家可能永远看不到在 updateHighScore() 中更新的值),但还不能解决许多潜在的原子性问题。 利用同步set-after-write 技巧可以消除可见性问题,因为 happens-before 排序是可传递的,因而调用 updateHighScore() 中的setAttribute() 和调用 getHighScore() 中的getAttribute() 之间有一个边缘地带。 因为 HighScore 状态的更新在 setAttribute() 之前发生,setAttribute() 状态的更新在从 getAttribute() 返回之前发生,getAttribute() 状态的更新在 getHighScore() 的调用方使用状态之前发生,所以通过这种传递可以得出结论:调用方 getHighScore() 看到的值至少和 setAttribute() 的最近一次调用一样新。 这个技巧称为利用同步(piggybacking on synchronization),因为 getHighScore() 和updateHighScore() 方法能够在 getAttribute() 和setAttribute() 中使用同步信息来提供一些可见性保证。 然而,在上面这个例子中,这还不能完全解决问题。 set-after-write 技巧可能对状态复制非常有用,但还不能提供线程安全。 了解不可修改性要创建线程安全的应用程序,一个有用的技巧便是尽可能多地使用不可修改的数据。 清单 4 展示了重写后的最高分示例,它使用了 HighScore 的不可修改的 实现,从而避免了原子性故障(允许调用方看见不存在的玩家/分数对)和可见性故障(阻止 getHighScore() 的调用方看见在调用 updateHighScore() 时写的最新值): 清单4. 使用不可修改的 HighScore 对象修复原子性和可见性漏洞 Public class HighScore { public final String name; public final int score; public HighScore(String name, int score) { = name; = score; } } public PlayerScore getHighScore() { ServletContext ctx = getServletConfig()(); return (PlayerScore) (highScore); } public void updateHighScore(PlayerScore newScore) { ServletContext ctx = getServletConfig()(); PlayerScore hs = (PlayerScore) (highScore); if ( > ) (highScore, newScore); } 清单4 中的代码的潜在故障很少。 在 setAttribute() 和getAttribute() 中使用同步保证了可见性。 实际上,仅存储单个不可修改数据项消除了潜在的原子性故障,即 getHighScore() 的调用方可以看见名字/分数对的不一致更新。 将不可修改对象放置在范围容器避免了许多原子性和可见性故障;将有效不可修改性 对象放置在范围容器中也是安全的。 有效不可修改性对象是指那些虽然理论上是可修改的,但实际上在发布之后再没有被更改过的对象,比如 JavaBean,将一个对象放置到 HttpSession 中之后,它的 setter 方法就不再被调用。 放置在 HttpSession 中的数据不仅被该会话的请求访问;它还可能被容器本身访问(如果容器进行状态复制的话)。 所有放置在 HttpSession 或ServletContext 中的数据应该是线程安全的或有效不可修改的。 影响原子状态转换但是清单4 中的代码仍然有一个问题 — updateHighScore() 中的check-then-act 仍然使两个试图更新最高分数的线程之间存在潜在 “争夺”。 如果计时失误,有一个更新可能会丢失。 两个线程可能同时通过了 “高于现有分数的新最高分” 检查,造成它们同时调用 setAttribute()。 不能确保两个分数中最高者获得调用,这取决于计时。 要修复这个最后的漏洞,我们需要一种原子性地更新分数引用的方法,同时又要保证不受干扰。 有几种方法可以实现这个目的。 清单5 为 updateHighScore() 添加了同步,确保更新进程中固有的 check-then-act 不和另一个更新并发执行。 如果所有条件修改逻辑获得 updateHighScore() 使用的同一个锁,用这种方法就可以了。 清单5. 使用同步修复最后一个原子性漏洞 public void updateHighScore(PlayerScore newScore) { ServletContext ctx = getServletConfig()(); PlayerScore hs = (PlayerScore) (highScore); synchronized (lock) { if ( > ) (highScore, newScore); } } 虽然清单 5 中的技术是可行的,但还有一个更好的技术:使用 包中的 AtomicReference 类。 这个类的用途就是通过 compareAndSet() 调用提供原子条件更新。 清单 6 展示了如何使用 AtomicReference 来修复本示例的最后一个原子性问题。 这个方法比清单 5 中的代码好,因为很难违背更新最高分数的规则。 清单6. 使用 AtomicReference 来修复最后一个原子性漏洞 public PlayerScore getHighScore() { ServletContext ctx = getServletConfig()(); AtomicReferenceholder = (AtomicReference) (highScore); return (); } public void updateHighScore(PlayerScore newScore) { ServletContext ctx = getServletConfig()(); AtomicReference holder = (AtomicReference) (highScore); while (true) { HighScore old = (); if ( >= ) break; else if ((old, newScore)) break; } } 对于放置在范围容器中的可修改数据,应该将它们的状态转换变成原子性的,这可以通过同步或 中的原子变量类来实现。 序列化对 HttpSession 的访问在我已给出的示例中,我试图避免与访问整个应用程序中的 ServletContext 相关的各种危险。 很明显,访问 ServletContext 时需要细心的协作,因为任何请求都可以访问 ServletContext。 然而,大多数有状态 Web 应用程序严重依赖于内嵌于会话的容器 HttpSession。 同一个会话中发生多个同步请求的原因不是很直观;毕竟,每个会话都是绑定到一个特定用户或浏览器会话的,并且用户不一定一次请求多个页面。 但是在编程式地生成请求的应用程序中(比如 AJAX 应用程序),一个会话中的请求是可以重叠的。 单个会话中的请求当然可以是重叠的,但这不是一件好事。 如果可以轻松地序列化会话中的请求,当访问 HttpSession 中的共享对象时,这里提到的所有问题几乎都可以解决;序列化可以阻止原子性故障,并且利用 HttpSession 中的同步可以阻止可见性故障。 序列化特定会话的请求不会对吞吐量造成很大的影响,因为一个会话中的请求很少重叠,在一个会话中出现很多请求重叠就更罕见了。 不幸的是,servlet 规范并没有提到 “序列化同一会话中的请求”。 不过 SpringMVC 框架提供了一种方法,并且这种方法可以在其他框架中轻松实现。 SpringMVC 控制器的基类 AbstractController 提供了一个布尔变量 synchronizeOnSession;设置这里之后,它将使用一个锁,确保一个会话中只同时执行一个请求。 序列化 HttpSession 上的请求消除了很多并发性危险。 同样,将对象限制在 Event Dispatch Thread(EDT)中减少了 Swing 应用程序中的同步需求。 结束语许多有状态 Web 应用程序有很严重的并发性漏洞。 在没有足够协调的情况下,访问存储在 HttpSession 和ServletContext 等范围容器中的可变数据就会产生这些漏洞。 开发人员通常会误认为 getAttribute() 和setAttribute() 方法中的同步已经足够 但这只能应付特定情况,比如当属性是不可修改、有效不可修改或线程安全的对象时,或当可能访问容器的请求被序列化时。 通常,放置在范围容器中的所有内容都应该是高度不可修改的或线程安全的。 servlet 规范提供的范围容器机制并不管理没有提供它们自己的同步的可变对象。 将普通的 JavaBean 类存储在 HttpSession 中是很大的隐患。 收起

你最倾向于将电子政务分成几个阶段

“互联网+”时代,针对电子政务发展的新方向,政府需要将履行职责和全面深化改革措施协调起来,找到电子政务的发展方向,实现最佳实践的目标。 在面临技术体系架构需向云计算转变,建设重点需从流程信息化向政府治理能力提升转变,政府信息资源开发利用需要从公开、共享、市场、安全四个方面整体推动,如此一来,相应的发展战略、发展规划、建设计划以及实践标杆,都需要匹配复合型人才,并且由集中统一的制度实施保障。 l 技术体系架构需向云计算转变云计算将是未来电子政务技术体系架构的重要方向。 互联网对电子政务发展的技术体系架构产生了重大影响,电子政务技术体系架构在开始建设的时候,是没有互联网这个因素的,互联网的发展使得计算模式发生重要改变,云计算资源利用率高,成本节约,模式改变集中体现就是云计算。 此外,模式的转变对于不同部门、不同地区、不同事物是多样性、分阶段的。 向云计算转变,方向毫无疑问,但在实际建设中,需要从长期经济发展和业务发展角度统筹考虑,需要从五年十年的角度,考虑哪个方式经济上是最合算的,哪个方式业务是最可以持续的,而不是单单追求理想中的最佳模式。 再者,传感技术、软件技术和内容技术将发挥重要作用。 政府履行职责,不管是公共服务,还是社会管理,都需要掌握更多的数据信息,传感技术为政府掌握更多信息,支撑履行职责创造了条件。 社会公众对信息技术的利用能力在大幅提升,政府提供公共服务和加强社会管理,都需要对既有软件系统重新思考。 互联网带来了海量数据,需要内容技术对海量数据进行管理和利用。 既有的信息管理的技术和系统需要适应这个变化,需通过新技术来变革。 l 建设重点需从流程信息化向政府治理能力提升转变电子政务建设的核心是“政务”。 电子政务要全面支撑政务部门履行职责,满足公共服务、社会管理、市场监管和宏观调控各项需求。 目前,中央政府正在深入推进简政放权改革的实施,简政放权目的是什么?第一、着力提升政府效能,提高政府行政效率与公共服务水平。 第二,加强和改进市场监管,增强政府服务和监管的有效性,简政放权行政权力下放不等于不管理不控制。 从这个角度来看,电子政务支撑政府履职需要从原来的流程出发转变向政务本质出发。 l 政府信息资源开发利用需要从四个方面整体推动 互联网的快速发展,数据信息的数量在急剧增长,做好信息资源管理变得尤为重要。 在“互联网+”时代,对于政府数据信息来讲,四个基本原则依然不能改变,第一是公开,第二是共享,第三是市场,第四是安全。 不管概念如何变化,政府信息资源开发利用也好,大数据也好, “互联网+”也好,这四点依然是基本原则,公开、共享、市场、安全四个原则缺一不可,如果只偏重一个方向,发展中必定会出现问题。 l 电子政务的最佳实践借鉴中国电子政务发展已经有三十多年的历程,发展历程中,取得了很多成绩,由于历史条件,技术条件等各方面制约,中国电子政务建设也走了一些弯路。 在新的环境和条件下,中国电子政务的未来,最佳实践变得更加重要。 最佳实践首先要有方向,没有方向最佳实践无从谈起,需要认真梳理,尤其是在”互联网+”时代,需要从政府履行职责和全面深化改革措施协调起来,找到电子政务的发展方向。 为了实现最佳实践的目标,需要重点考虑以下几个问题:第一,要有发展战略。 确定电子政务的发展目标、原则和方向。 第二,要有发展规划。 要把重大任务予以明确,找出实现目标的困难和解决的措施。 第三,要有建设计划。 不仅要有年度计划和项目计划,还要建立一套评价和实施的指标体系,来规划和监督计划的实施。 第四,要有实践标杆。 发展方向是抽象的,如何实现是关键,从国际到国内,电子政务建设有很多成功案例,需要将这些成功案例做好总结,从具体的行动决策和技术架构总结为有普遍规律性、理论性、操作性的实践参考。 第五,要有复合型人才。 电子政务的持续发展需要高端的复合型人才,人才的积累需要一个可持续发展过程,未来要以CIO制度为基础,推动人才的可持续发展。 第六、要有集中统一的制度保障。 集中统一是电子政务发展的基本原则,在实际实施的过程中,贯彻落实是难题,电子政务发展较好的地区和部门,很重要的就是做到了集中统一,所以集中统一的制度保障十分重要,金鹏信息电子政务软件。