一种基于有状态方面的BPEL流程运行时监控方法
技术领域
本发明属于计算机网络应用领域,具体涉及一种基于有状态方面的BPEL流程运行时监控方法。
背景技术
随着Internet的快速发展,传统计算范型难以应对Internet复杂计算环境和业务敏捷性需求带来的新挑战。面向服务计算(Service Oriented Computing,SOC)正在成为新一代计算范型,SOC描绘了服务以开放、自主的方式运行在分布节点上,通过跨Internet的互联、互通、协同、联盟构造应用,系统能够根据环境变化和业务需求动态适应的新型应用图景。
SOC利用服务作为基本构造单元,支持分布式应用的快速、低成本的组合式开发。服务是自治的、平台独立的计算实体,支持以平台无关的方式进行使用。Web服务(WebServices)是当前实现SOC计算范型最有前景的技术。Web服务的最大优势是采用开放技术标准,例如:采用XML语言描述服务接口和服务调用,采用HTTP等Internet标准通信协议进行传输等,这些开放标准的使用,也使得Web服务成为跨异构系统集成的最佳技术选择。
单个Web服务所能够提供的功能有限,服务复合(Service Composition)通过组合现有的Web服务从而创建新的、高层的Web服务以获取新的服务功能,已成为在Internet上构建业务流程和开发分布式应用的主要方法。在开发基于复合服务的应用中,通常由一个中心节点按照预定义的流程执行活动,并对参与方的交互进行协调。WS-BPEL(Business ProcessExecution Language for Web Services)是OASIS标准化组织所批准的一个面向流程的复合服务编制语言,BPEL流程定义了参与服务之间的控制流和数据流,已经成为复合服务开发的事实标准(参见文献:http://docs.oasis-open.org/wsbpel/2.0/wsbpel-v2.0.pdf)。
如使用BPEL语言描述在线旅行预定业务流程,该流程通过组合Internet上已存在的酒店预定、机票预定和在线支付等Web服务,为用户提供一站式的旅行预定服务。其具体过程如下:在接受到用户的旅行预定请求后,验证用户的登陆信息,登陆成功后,调用酒店预定服务和机票预定服务。为了吸引更多的用户,该流程还提供搜索服务,返回酒店附近的商场信息,并将各种信息进行汇总,返回给用户等待确认,若用户对预定结果不满意,可重新进行预定。最后,在用户对预定结果满意后,流程调用支付服务,完成在线支付。
在软件开发的过程中,存在大量的横切关注点(cross-cutting concerns),典型的如:日志、事务功能等。这些关注点无法很好的封装在单个模块中,通常会贯穿整个软件系统,从而产生代码交织和代码散布的现象,影响模块的内聚性和模块之间的独立性。
面向方面的软件开发方法(Aspect-oriented Software Development,AOSD)旨在提高软件开发过程中横切关注点分离,通过引入方面(Aspect)模块化软件开发方法中的各种横切关注点。AOP引入称为方面(Aspect)的模块单元以解决复杂系统中的横切关注点问题,面向方面的程序设计包含三个关键的概念:连接点(Joinpoint)、切入点(Pointcut)和通知(Advice)。为了支持面向方面的软件开发,目前已经存在很多的面向方面的编程开发语言,本发明以Java语言的面向方面扩展AspectJ(参见文献:G.Kiczales,E.Hilsdale,J.Hugunin,M.Kersten,J.Palm,and W.G.Griswold.An overview of aspectj.In ECOOP’01,pages327-353,2001)来解释三个概念的含义:
连接点(Joinpoint):是程序执行过程中定义明确的点。在程序执行中哪些点被定义为连接点由面向方面语言的连接点模型决定。由于AspectJ是Java语言的一个面向方面扩展,其连接点模型定义为面向对象程序执行中的方法调用、成员访问等。
切入点(Pointcut):为了模块化横切关注点,需要一种方法识别相关的连接点。切入点是对连接点属性的断言,可基于参数类型或返回值类型来选择相关的方法执行点,或使用通配符匹配感兴趣的连接点。例如:AspectJ中的切入点语言支持通配符选择相关的get和set执行点集合,构造函数集以及异常处理集等。
通知(Advice):用于声明在切入点表达式中定义的连接点被调用时执行的动作。通知代码能被嵌入到调用者和被调用者之间,方法调用者和方法本身之间,可在连接点执行前、执行后执行,或者替换当前的连接点。在AspectJ定义了三种通知类型:before,after和around,分别对应于连接点执行前,执行后和旁路当前的连接点。
将方面与目标程序集成的过程称为编织(weaving)。通常有两种编织方法:静态编织和动态编织。静态编织方法通常借助于预编译器在目标程序执行前将方面织入目标程序;动态编织发生在目标程序执行时,通常采用专有的技术在运行时将方面与目标程序进行编织,例如:Spring AOP采用Java动态代理(dynamic proxy)在运行时拦截方法调用,织入方面逻辑。
同样在基于WS-BPEL语言开发的复合服务中,也存在大量的横切关注点,BPEL流程的运行时监控就是一个典型的横切关注点。运行时监控是复合服务执行时必不可缺的一个环节。原因在于:
1)从计算环境的复杂性角度看:复合服务的构造和执行依赖于自治的第三方服务,所需要的服务可在复合服务运行时动态的查找,并进行绑定调用。这种动态性尽管给复合服务的开发带来很强的灵活性,但是却对系统的正确性带来很大的影响。传统的软件正确性验证是静态的,在系统正式运行之前进行,构成软件系统的各个组件都是预先可知的,在应用部署之后不需要进一步的验证。但对复合服务而言,所依赖的第三方服务通常是独立开发和运行,在部署后其行为也可能发生改变,系统的正确性无法事先得到保证。
2)从上层业务敏捷性的角度来看:在业务流程设计时通常会设计与特定业务领域相关的业务策略或称为业务规则,业务规则的一个重要特点是快速变化,并且可重用。在复合服务设计时,如果将快速变化的业务策略与业务逻辑进行混合,会导致设计出的流程规范复杂度的增加,业务逻辑难于理解,并且不够灵活,缺乏适应性。
以旅行预定流程为例,说明复合服务中典型的监控需求:
1)检查流程实例的运行是否违背预先指定的行为约束。例如可以指定如下的监控需求:在用户的取消旅行预定请求被接收之前,以预定的酒店房间和机票必须被成功取消。如果在运行时检测到约束违背,则应及时补偿已完成的活动,并通知流程管理者;
2)由于BPEL流程的正确性依赖于自治的第三方服务,因此需要在运行时对外部服务的行为进行监控。例如当用户取消酒店入住请求时,取消请求可能被接收或拒绝,但是根据酒店服务与旅行预定流程双方之间的服务水平级协议:在调用支付服务之前,取消酒店入住请求都应当被成功接受,如果该约束违反,流程重试该取消操作或动态替换提供相同功能的服务,以满足用户的旅行预定请求。
3)监控流程执行还可以动态实施业务策略。例如:为了吸引更多的用户,流程管理者可以指定如果预定的机票数超过20,预定的房间数超过10,可给予用户10%的优惠。
BPEL语言的主要不足在于不支持关注点分离,缺乏对BPEL流程运行时监控的模块化关注机制,监控代码分散在BPEL流程中的各个部分,与业务逻辑缠结,增加了流程开发的复杂度以及日后的可维护性,导致设计出的流程不够灵活,缺乏一定的适应性。
目前已经有很多工作对BPEL语言做出扩展,以模块化描述业务流程中的各种横切关注点。C.Courbis和A.Finkelstein(参见文献:C.Courbis and A.Finkelstein.Towards aspectweaving applications.In ICSE’05,pages69-77,2005)提出一个针对BPEL语言的方面扩展,在所提出的面向方面的扩展中,使用XPath作为切入点语言,使用Java语言编写通知代码。该工作使用AOP机制实现可扩展、可配置的BPEL引擎,在引擎级别模块化各种横切关注点,如日志和调式等功能。为支持复合服务运行时结构的动态调整,使用BPEL语言作为通知语言,并使用动态编织技术,通过动态修改内存对象树,以支持流程结构的动态调整。
AO4BPEL(参见文献:A.Charfi and M.Mezini.Ao4bpel:An aspect-oriented extension tobpel.World Wide Web,10(3):309-344,2007)允许模块化表示业务流程中的各种横切关注点。AO4BPEL使用XPath作为切入点语言,以捕获复合服务执行时活动连接点。在Advice语言的选用方面,为了支持运行时的复合服务在流程级别的动态调整并与目标语言保持一致,使用BPEL语言作为通知语言。与Courbis工作的不同之处在于,AO4BPEL除了支持活动级的连接点,还支持内部连接点,以支持安全、可靠消息等非功能属性的实施。
目前大部分针对BPEL语言的AOP扩展中,方面被限制在仅能观察流程当前执行的连接点,而无法观察流程的执行历史,表达较为复杂的流程监控需求,如前面提及的对旅行预定的监控需求。″Stateful Aspect″高级的AOSD特性目前并不支持。使用该技术,方面可以观察目标程序的执行历史,当感兴趣的事件序列发生时,执行相应的通知代码。
Padus是一个面向方面的BPEL扩展语言(参见文献:M.Braem and D.Gheysels.History-based aspect weaving for ws-bpel using padus.In ECOWS’07,pages159-167,2007)。Padus使用基于逻辑的切入点语言,使用正则表达式表达基于历史的切入点,但表达能力有限,无法表达各种行为约束,如对旅行预定流程的监控需求1和2,能够表达事件之间的各种时序关系是设计有表达力的切入点语言的关键。此外Padus使用静态的编织技术,对流程的侵入性较强,并且不够灵活,缺乏一定的适应性,当方面发生变化时,需要终止正在运行的流程并重新进行编织。
现有针对BPEL的面向方面扩展不足在于无法观察流程的执行历史,或者表达能力不足,不支持表达流程执行时事件之间的各种时序关系,无法表达较为复杂的监控横切关注点。
发明内容
为解决上述问题,本发明提出一种针对WS-BPEL语言有状态方面扩展(Stateful AspectExtension),表达BPEL流程监控中复杂的监控需求,并通过动态编织技术,观察流程的运行时行为,当指定的监控需求发生时,方面执行相应的动作对运行时流程实例进行管理,包括以下内容:
1)对现有基于XPath的切入点进行扩展,定义了基于历史的切入点语言,基于历史的切入点语言包括捕获事件之间时序关系的pattern操作符和表达监控范围的range操作符。
2)为了在运行时自动实施监控,给出基于历史的切入点语言的自动机语义。
3)用BPEL语言作为通知代码对BPEL流程进行监控。
4)使用动态编织技术实现有状态方面,直接访问内部的流程表示及流程实例状态,对流程实例进行运行时监管。
下面详细介绍具体发明内容:
1.基于历史的切入点语言语法定义
如图1所示,基于历史的切入点由pattern(行为模式)和range(范围)两个部分构成,构成pattern和range的基本元素是eventcut。
eventcut:定义了pattern和range中的基本事件。对于流程执行时的遇到的每个活动,当进入活动连接点时标识当前活动的开始事件,当离开连接点时,标识当前活动的结束事件。基于Xpath表达的切入点,本发明用标识符entry表示捕获活动的开始事件,用标识符exit表示捕获活动的结束事件。
conditon:由于切入点可暴露指定连接点附近的上下文信息,因此可以对活动连接点的变量信息指定约束条件,以表达感兴趣的事件(eventcut)。例如:<exit name=“E1”condition=“$outcome/confirm==true”>//receive[@partnerlink=“hotel”@operation=“cancel”]</exit>捕获取消酒店预定的请求已被成功接受的receive活动结束事件。目前conditon支持典型的布尔操作,如“&&”和“‖”;关系操作,如“<”,“>”和“==”;数学操作符,如“+”,“-”,“*”和“/”。
pattern:指定事件之间的时序关系,分为执行pattern和约束pattern。所定义的pattern操作符以tracecut作为参数。Tracecut既可以捕获基本事件(event),也可以捕获复合事件(通过执行pattern),基本事件和复合事件统称为事件。
执行pattern:捕获流程执行时产生的复合事件。基于eventcut,本发明定义了三种执行pattern操作符:any/all/seq。操作符的具体含义如下:
1)any以一组tracecut作为参数,如any(E1,E2,...,En)当其中任何tracecut所表示的事件发生时,该复合事件发生,其中,E1,E2,...,En表示tracecut捕获的事件。
2)seq以一组tracecut作为参数,如seq(E1,E2,...,En)。其含义为当指定的事件按顺序发生时,指定的复合事件发生。
3)all以一组tracecut作为参数,当所有指定的事件发生时,指定的复合事件发生,与seq不同,该操作符不指定事件发生的顺序。
Pattern以tracecut作为参数,即允许在pattern中嵌套定义执行pattern,例如seq(E1,all(E2,E3))中,seq执行pattern的第二个参数是一个all执行pattern。
目前,对于约束pattern,支持如下五种操作符(E,E’为tracecut所捕获的事件):
1)E absent限制指定的事件E不发生;
2)E exist指定的事件E必须发生;
3)E exist[at least]|[at most]n times:对exist进行了扩展,限定了事件发生的次数。其中:E exist n times限定事件恰好发生n次;E exist at least n times限定事件至少发生n次;E existat most n times限定事件至多发生n次;
4)E precede E’:指定在E’发生之前,必须至少有一个事件E发生;
5)E leadto E’:指定E发生后,事件E’必须发生;
目前本发明定义了五种类型的range,包括global、before、after、between-and和after-until(S和T表示eventcut所捕获的事件),其含义如下:
1)global:关注整个流程的执行历史。
2)before T:关注从流程开始到所指定事件的第一次发生之间的流程执行历史。
3)after S:关注指定事件第一次发生之后的流程行为。
4)between S and T:关注从事件S开始到事件T结束之间的流程执行历史。
5)after S until T:与between-and类似,关注从事件S开始到事件T结束之间的流程执行历史,区别在于结束事件T可不发生。
between-and和after-until所表达的范围在流程执行过程中可重复发生。此外,为了方便在运行时实施监控,进一步限定range事件和构成pattern的事件不相同。
2.基于历史的切入点语言的自动机语义
前面介绍了基于历史切入点各组成部分含义,为了在运行时自动的实施监控,需要定义其形式化的语义。由于自动机易于理解,具有严格语义并且可直接用于运行时监控的特点,在所提出的方法中,选用自动机描述基于历史切入点的语义。
目前对于运行时监控的研究主要来源于两个社区:面向方面的社区和运行时验证社区。运行时验证社区支持基于跳跃(skipping-based)的自动机语义,本发明采用面向方面社区所支持的基于过滤(filtering-based)的自动机语义。
以正则表达式‘AB’为例,说明两种不同语义情况下自动机表示的区别。在基于跳跃的语义下,‘AB’的含义为“A发生后,B最终发生”,即在A和B之间允许其他事件发生,在基于过滤的语义下,‘AB’的含义为“A发生后下一个事件即为B”。
图2给出了约束pattern基于过滤语义的自动机表示:
对于执行pattern“seq/any/all”,由于所构造的复合事件等价于正则表达式,因此可以给出其基于自动机的表示。
为了识别any(E
1,E
2,...,E
n)和all(E
1,E
2,...,E
n)所表达的复合事件,首先为每个事件构造自动机A(E
i),再通过笛卡尔乘机构造乘机自动机
图3(a)给出了为识别复合事件any(E
1,E
2)和all(E
1,E
2)所构造的乘机自动机。对于图3(a)中的乘积自动机,{00}表示自动机的初始状态,any(E
1,E
2)复合事件的终止状态为{10,01,11};all(E
1,E
2)复合事件的终止状态为{11}。
对于复合事件Seq(E1,E2,...,En),所构造的自动机如图3(b)所示。遵循基于过滤的自动机语义,在seq(E1,E2,...,En)表示的复合事件中,E1,E2,...,En顺序发生,并且任意相邻的两个事件之间不允许发生其他事件。
目前为止,给出了基于历史的切入点中pattern的自动机表示。在所提出的基于历史的切入点中,每一个pattern都有一个range,表达了pattern监控的范围。下面给出添加range之后的pattern自动机表示。主要考虑加入before、after、after-until和between-and后的pattern自动机表示,对于global range,pattern的自动机表示保持不变。图4给出了加入range后P leadto Q的自动机语义。对于执行pattern中seq表达的复合事件,以seq(E1,E2)为例,加入range之后的自动机表示如图5所示。
3.用BPEL语言作为通知代码对BPEL流程进行监控
在流程运行期间,当指定的监控需求发生时,需要执行适当的动作对流程实例进行干预和调整。与被监控对象保持一致,本发明选用BPEL语言作为通知代码。但是BPEL语言只提供了简单的故障处理机制(如fault handler和compensation handler),不支持较为复杂的管理动作。本发明提供以下几个常用的流程管理操作:retry(重试),alternate(替换)和skip(跳跃)。
1)retry(S,number,duration)
retry的含义为重试所指定的活动S,number指定了重试的上限,duration指定了两次重试的间隔时间。例如:<retry activity=“scope[@name=‘cancel_hotel’]”number=“5”duration=“PT3S”/>表示每隔3秒重试scope活动“cancel_hotel”,重试的最大次数为5次。
2)alternate(S,url,servicename)
alternate通过动态绑定到url和servicename标识的服务以替换活动S中的伙伴服务。目前假设替换服务和被替换服务有相同的接口,并且提供相同的功能。
3)skip(S)
skip跳过所指定的活动S。在流程执行中可能由于时间和价格方面的约束,而需要跳过某个可选的活动,实现对流程实例结构的动态调整。
4.采用动态编织技术实现有状态方面,实现对流程的运行时监管
编写好有状态的方面后,需要与业务流程进行编织,以在运行时对流程进行监管。通常有两种编织方法:静态编织和动态编织。静态编织通常借助预编译技术在流程执行前,将方面代码织入到BPEL流程中。动态编织技术在流程运行时将方面代码与业务流程进行编织。静态编织的不足在于对流程代码具有一定的侵入性,编织后的BPEL流程将混合监控代码,并且缺乏一定的灵活性,当方面修改后,需要与业务流程重新进行编织。动态编织的灵活性强,允许在运行时动态的加载、删除和修改方面,并且对目标流程的侵入性较小,因此采用动态的编织机制实现有状态的方面,在具体实施方式部分将进行详细介绍。
本发明的优点和积极效果如下:
1、基于有状态方面来表达复杂的监控需求,监控逻辑与业务逻辑分离,流程开发人员只需关注核心的业务逻辑,降低了业务流程开发的复杂度,提高了流程的灵活性和适应性。
2、监控逻辑与业务流程动态编织,对目标程序的侵入性较小,并支持监控逻辑运行时修改和配置。当需要修改监控逻辑时,只需重新部署方面,无需修改业务流程。
3、本发明可为基于BPEL表达的业务流程提供监控和管理支持,当指定的监控需求发生时,可及时对流程进行干预和调整,提高了流程的适应性。
附图说明
图1基于历史的切入点语法定义;
图2约束pattern的自动机语义;
其中,(a)为“P precede Q”的自动机语义;(b)为“P leadto Q”的自动机语义;
(c)为“P exist”的自动机语义;(d)为“P absent”的自动机语义;
(e)为“P exist exactly n times”的自动机语义;
(f)为“P exist at least n times”的自动机语义;
(g)为“P exist at most n times”的自动机语义;
图3all(E1,E2)、any(E1,E2)和seq(E1,E2,...,En)的自动机语义;
其中,(a)为all(E1,E2)、any(E1,E2)的自动机语义;
(b)为seq(E1,E2,...,En)的自动机语义;
图4加入range后P leadto Q的自动机语义;
其中,(a)为P leadto Q中加入“before T”后的自动机语义;
(b)为P leadto Q中加入“after S”后的自动机语义;
(c)为P leadto Q中加入“afeer S until T”后的自动机语义;
(d)为P leadto Q中加入“between S and T”后的自动机语义;
图5加入range后seq(E1,E2)的自动机语义;
其中,(a)为seq(E1,E2)中加入“before T”后的自动机语义;
(b)为seq(E1,E2)中加入“after S”后的自动机语义;
(c)为seq(E1,E2)中加入“between S and T”后的自动机语义;
(d)为seq(E1,E2)中加入“afeer S until T”后的自动机语义;
图6有状态方面的实现架构;
图7监控过程流程图。
具体实施方式
为了实现有状态的方面,在运行时对BPEL流程进行监控和管理,需要捕获流程运行时产生的事件序列,检查与指定的监控需求是否一致,并实施相应的管理动作。以下结合图示,对采用动态编织技术的有状态方面实现进行详细说明。图6给出了基于面向方面技术的pattern监控和advice实施架构,主要包含方面部署工具和运行时的方面扩展两部分构成。
1.方面部署
方面部署包括方面实例化和方面交互两部分。方面实例化指定如何将方面实施于被监控的目标流程,目前支持流程级方面实例化和实例级方面实例化两种方式。使用流程级方面实例化,部署的方面将应用于所有的流程实例。使用实例级方面实例化,方面被应用到指定的流程实例上。为了支持对指定流程实例的监控,可以在方面部署文件中指定对流程变量的约束。
方面交互指定当有多个监控需求同时发生时,按照部署文件中指定的顺序执行通知代码。如果没有指定通知的执行顺序,则按“先部署先执行”的策略执行通知代码。
2.运行时方面扩展模块
运行时的方面扩展允许监控流程执行期间产生的事件序列,以及通知代码的BPEL流程的动态编织。该扩展本身使用AspectJ实现为一个方面,并与BPEL引擎代码进行编织。
1)BPEL引擎:BPEL解释器(interpreter)在运行时基于visitor设计模式自顶向下访问BPEL流程文件编译后生成的抽象语法树(AST,abstract syntax tree)。
2)方面注册模块:保存所有已部署的Aspect信息,当一个有状态方面被部署时,在抽象语法树上遍历查找切入标识的感兴趣活动节点,并将相关的eventcut信息(如eventcut名字)存储到内部的数据结构中。当方面部署时,同时会生成一个监控器配置文件,保存了pattern和range的相关信息,并交于监控管理器处理。
3)监控管理器:保存所有已部署的监控器信息。监控管理器包含一个parser模块,通过读取监控器配置文件并依据Pattern&Range自动机模板库,生成监控器信息。监控管理器中包含一个事件树数据结构,以组织多个自动机之间的层次关系。事件树由根节点,非终结节点,叶节点以及关联节点的边构成。根节点保存历史切入点所对应的自动机信息,非终端节点保存内部执行pattern所对应的自动机信息,非终端节点可能有多条输入边和输出边,叶节点代表基本的事件。
4)方面管理器:是负责管理监控过程的主要模块,使用AspectJ与BPEL引擎进行编织。在编织后,该模块可直接访问内部的流程表示及流程实例状态。
有状态方面的具体实施过程如下:
1)使用OnceBPEL管理控制台提供的流程部署工具对WS-BPEL语言表达的业务流程进行部署。在部署过程中调用BPEL引擎提供的parser模块进行编译,生成抽象语法树(AST)。
2)使用本发明提出的有状态方面指定对业务流程的监控和管理需求,并进行方面的部署。在指定被监控的流程后,调用方面注册模块进行方面的注册。
3)运行时的监控过程如下:在一个活动执行前和执行后,方面管理器向方面注册模块查询标识该活动的eventcut信息。方面管理器维护被监控流程实例和监控器实例之间的映射,如果eventcut中所指定的条件满足,方面管理器执行管理动作,把事件发送到正确的监控器实例。当被监控流程的第一个range开始事件发生后,方面管理器通知监控管理器创建一个新的监控器实例。监控器实例记录流程的执行历史,并检查指定的监控需求是否满足,具体的检查过程如图7所示。
当监控器实例接收到来自监控管理器的事件时,代表该事件的叶节点将被激活,并根据输出边触发其父节点。当父节点代表的自动机接收到该事件后,进行事件匹配,并发生状态转换,若自动机进入结束状态,则将向父节点发送代表该节点的复合事件标识符。在事件树中,数据流和控制流都是从叶节点流向根节点。如果根节点代表一个约束pattern,则当对应的自动机进入约束违背状态,触发方面管理器执行相应的通知代码。如果根节点代表一个执行pattern,则当自动机进行终结状态后,执行相应的通知代码。
3.通知实施机制
由于使用BPEL语言编写通知代码,因此在advice具体实施时,Aspect管理器将通知代码交由BPEL引擎执行,实现对流程实例的运行时管理。
对于扩展的retry和alternate动作,由于需要访问内部的流程变量和改变流程的行为,本发明将其转换成BPEL代码,并动态的编织到流程引擎中。其中alternate的实现使用了BPEL语言提供的动态的partner决策机制(dynamic partner resolution);retry的实现转换成while活动,在循环条件中限定执行次数,并使用BPEL提供的wait指定两次活动执行之间的间隔时间;为了支持skip动作,Aspect管理器在运行时动态生成一个方面:其中切入点标识待跳过的活动,属性标识需要动态调整的流程实例,通知的类型是around。