对于最新稳定版本,请使用Spring Framework 7.0.1spring-doc.cadn.net.cn

宣布切角

点切确定连接点,从而使我们能够控制 当建议流逝时。Spring AOP 仅支持 Spring 的方法执行连接点 所以你可以把点割看作是与Spring上方法的执行匹配 豆。点切声明包含两部分:一个包含姓名的签名和任意 参数和一个精确确定方法的点切表达式 我们感兴趣的处决。在AOP的@AspectJ注释风格中,点切割 签名由正则方法定义提供,点割表达式为 通过使用以下方式表示@Pointcut注释(作为点切割签名的方法) 必须有无效返回类型)。spring-doc.cadn.net.cn

举个例子可以帮助区分点切割签名和点切割 表情清晰。以下示例定义了一个名为anyOldTransfer那 匹配任意名为 的方法的执行转移:spring-doc.cadn.net.cn

@Pointcut("execution(* transfer(..))") // the pointcut expression
private void anyOldTransfer() {} // the pointcut signature
@Pointcut("execution(* transfer(..))") // the pointcut expression
private fun anyOldTransfer() {} // the pointcut signature

构成@Pointcut注释是正则的 AspectJ 点切割表达式。关于AspectJ点切割语言的完整讨论,请参见 AspectJ 编程指南(以及扩展版 AspectJ 5 开发者笔记)或AspectJ相关书籍(如Colyer的《Eclipse AspectJ》 等人,或拉姆尼瓦斯·拉达德的《行动中的面貌》)。spring-doc.cadn.net.cn

支持的点切指定符

Spring AOP 支持以下 AspectJ 点切割标识符(PCD),用于 pointcut 表达 式:spring-doc.cadn.net.cn

  • 执行: 用于匹配方法执行连接点。这是主场 用于使用 Spring AOP 的 pointcut 指示符。spring-doc.cadn.net.cn

  • : 限制匹配以在某些类型内连接点(执行 在使用 Spring AOP 时,在匹配类型内声明的方法)。spring-doc.cadn.net.cn

  • : 限制匹配到连接点(使用 Spring 时方法的执行 其中 bean 引用(Spring AOP 代理)是给定类型的实例。spring-doc.cadn.net.cn

  • 目标:限制匹配到连接点(使用时方法的执行) Spring AOP)中目标对象(代理的应用对象)是一个实例 该类型。spring-doc.cadn.net.cn

  • args: 限制匹配到连接点(使用 Spring 时方法的执行 AOP)中,参数是给定类型的实例。spring-doc.cadn.net.cn

  • @target:限制匹配到连接点(使用时方法的执行) Spring AOP)中,执行对象的类具有给定类型的注释。spring-doc.cadn.net.cn

  • @args: 限制匹配到连接点(使用 Spring 时方法的执行 AOP)中实际传递参数的运行时类型带有 给定类型。spring-doc.cadn.net.cn

  • @within:在满足给定的类型内,匹配点的连接极限 注释(在 使用春季AOP)。spring-doc.cadn.net.cn

  • @annotation:将匹配限制为连接点,且连接点的主语 (Spring AOP 中运行的方法)具有给出的注释。spring-doc.cadn.net.cn

其他切角类型

完整的AspectJ点切割语言支持额外的点切割标识符,但这些标识符并非 春季支持:,获取,设置,预初始化,静态初始化,初始化,处理器,建议执行,代码内,克洛夫,下面,如果,@this@withincode.在 pointcut 中使用这些 pointcut 指定符 Spring AOP 解释的表达式得到IllegalArgumentException存在 扔。spring-doc.cadn.net.cn

Spring AOP支持的点切指定符集未来可能会被扩展 支持更多AspectJ点切割标识符的版本。spring-doc.cadn.net.cn

由于 Spring AOP 仅将匹配限制在方法执行连接点,上述讨论 点切指示符给出的定义比你在 AspectJ编程指南。此外,AspectJ本身具有基于类型的语义,且在 执行连接点,两者兼有目标指向同一对象:该 对象执行该方法。Spring AOP 是一个基于代理的系统,具有区别 在代理对象本身之间(该对象绑定于)以及 代理(绑定于目标).spring-doc.cadn.net.cn

由于 Spring AOP 框架基于代理的特性,目标对象内部调用 按定义,是不被截获的。对于JDK代理,只有公共接口方法。 代理上的通话可以被拦截。在CGLIB中,公有和受保护的方法调用 代理会被拦截(甚至如有必要,也可以用包可见的方法)。然而 通过代理的常见交互应始终通过公开签名设计。spring-doc.cadn.net.cn

注意,点割定义通常会与任何截获的方法进行匹配。 如果一个点割严格只针对公有,即使在 CGLIB 代理场景中 通过代理进行潜在的非公开互动,需要相应定义。spring-doc.cadn.net.cn

如果你的拦截需求包括方法调用,甚至目标内的构造子 类,考虑使用Spring驱动的原生 AspectJ 织造 Spring基于代理的AOP框架。这构成了AOP使用方式的不同 各有不同特性,所以一定要熟悉编织 然后才做决定。spring-doc.cadn.net.cn

Spring AOP 还支持一个额外的 PCD,名为.这个PCD允许你限制 将连接点与特定命名的春豆或一组命名的 春季豆(使用万用卡时)。这PCD的形式如下:spring-doc.cadn.net.cn

bean(idOrNameOfBean)

豆豆的名字Tokens可以是任何春季豆的名字。有限外卡 游戏提供了使用该角色的辅助,所以如果你确定了一些命名 春季Beans的惯例,你可以写一个*PCD表达 去选择他们。与其他点切标记一样,PCD可以 与(且)一起使用,&&||(或),且!(否定)操作员也一样。spring-doc.cadn.net.cn

PCD仅在春季AOP中支持,不支持。 母语AspectJ编织。它是针对标准PCD的Spring专用扩展, AspectJ 定义了 ,因此不适用于在@Aspect型。spring-doc.cadn.net.cn

PCD在实例层面运行(基于Spring Bean名称 概念)而不仅仅是类型层面(基于织布的AOP仅限于类型层面)。 基于实例的点切割标识符是 Spring 的一项特殊功能 基于代理的AOP框架及其与Spring Bean工厂的紧密集成,其中 通过名称识别特定Beans是自然且简单的。spring-doc.cadn.net.cn

结合点切割表达式

你可以通过以下方式组合点切割表达式&&, ||!.你也可以参考 点切表达式按名称。下例展示了三个点割表达式:spring-doc.cadn.net.cn

package com.xyz;

public class Pointcuts {

	@Pointcut("execution(public * *(..))")
	public void publicMethod() {} (1)

	@Pointcut("within(com.xyz.trading..*)")
	public void inTrading() {} (2)

	@Pointcut("publicMethod() && inTrading()")
	public void tradingOperation() {} (3)
}
1 publicMethod如果方法执行连接点代表执行,则匹配 任何公开方式。
2 在贸易中如果方法执行在交易模块中,则匹配。
3 贸易运营如果方法执行代表 中的任何公共方法,则 匹配 交易模块。
package com.xyz

class Pointcuts {

	@Pointcut("execution(public * *(..))")
	fun publicMethod() {} (1)

	@Pointcut("within(com.xyz.trading..*)")
	fun inTrading() {} (2)

	@Pointcut("publicMethod() && inTrading()")
	fun tradingOperation() {} (3)
}
1 publicMethod如果方法执行连接点代表执行,则匹配 任何公开方式。
2 在贸易中如果方法执行在交易模块中,则匹配。
3 贸易运营如果方法执行代表 中的任何公共方法,则 匹配 交易模块。

最佳实践是从更小的命名结构构建更复杂的点割表达式 如上所示的点割。当以名称提及点切时,正常的 Java 可见性 规则适用(你可以看到私人同类型的点割,保护点切入 等级制度,公共任意点切,诸如此类)。可见度不会影响 点切匹配。spring-doc.cadn.net.cn

分享命名点切定义

在处理企业应用时,开发人员通常需要参考 应用模块和多个方面的特定作集。 我们建议定义一个专门的类,捕捉常用的命名点割表达式。此类类别通常类似于以下内容共同点割举个例子(不过你给职业起什么名字由你决定):spring-doc.cadn.net.cn

package com.xyz;

import org.aspectj.lang.annotation.Pointcut;

public class CommonPointcuts {

	/**
	 * A join point is in the web layer if the method is defined
	 * in a type in the com.xyz.web package or any sub-package
	 * under that.
	 */
	@Pointcut("within(com.xyz.web..*)")
	public void inWebLayer() {}

	/**
	 * A join point is in the service layer if the method is defined
	 * in a type in the com.xyz.service package or any sub-package
	 * under that.
	 */
	@Pointcut("within(com.xyz.service..*)")
	public void inServiceLayer() {}

	/**
	 * A join point is in the data access layer if the method is defined
	 * in a type in the com.xyz.dao package or any sub-package
	 * under that.
	 */
	@Pointcut("within(com.xyz.dao..*)")
	public void inDataAccessLayer() {}

	/**
	 * A business service is the execution of any method defined on a service
	 * interface. This definition assumes that interfaces are placed in the
	 * "service" package, and that implementation types are in sub-packages.
	 *
	 * If you group service interfaces by functional area (for example,
	 * in packages com.xyz.abc.service and com.xyz.def.service) then
	 * the pointcut expression "execution(* com.xyz..service.*.*(..))"
	 * could be used instead.
	 *
	 * Alternatively, you can write the expression using the 'bean'
	 * PCD, like so "bean(*Service)". (This assumes that you have
	 * named your Spring service beans in a consistent fashion.)
	 */
	@Pointcut("execution(* com.xyz..service.*.*(..))")
	public void businessService() {}

	/**
	 * A data access operation is the execution of any method defined on a
	 * DAO interface. This definition assumes that interfaces are placed in the
	 * "dao" package, and that implementation types are in sub-packages.
	 */
	@Pointcut("execution(* com.xyz.dao.*.*(..))")
	public void dataAccessOperation() {}

}
package com.xyz

import org.aspectj.lang.annotation.Pointcut

class CommonPointcuts {

	/**
	 * A join point is in the web layer if the method is defined
	 * in a type in the com.xyz.web package or any sub-package
	 * under that.
	 */
	@Pointcut("within(com.xyz.web..*)")
	fun inWebLayer() {}

	/**
	 * A join point is in the service layer if the method is defined
	 * in a type in the com.xyz.service package or any sub-package
	 * under that.
	 */
	@Pointcut("within(com.xyz.service..*)")
	fun inServiceLayer() {}

	/**
	 * A join point is in the data access layer if the method is defined
	 * in a type in the com.xyz.dao package or any sub-package
	 * under that.
	 */
	@Pointcut("within(com.xyz.dao..*)")
	fun inDataAccessLayer() {}

	/**
	 * A business service is the execution of any method defined on a service
	 * interface. This definition assumes that interfaces are placed in the
	 * "service" package, and that implementation types are in sub-packages.
	 *
	 * If you group service interfaces by functional area (for example,
	 * in packages com.xyz.abc.service and com.xyz.def.service) then
	 * the pointcut expression "execution(* com.xyz..service.*.*(..))"
	 * could be used instead.
	 *
	 * Alternatively, you can write the expression using the 'bean'
	 * PCD, like so "bean(*Service)". (This assumes that you have
	 * named your Spring service beans in a consistent fashion.)
	 */
	@Pointcut("execution(* com.xyz..service.*.*(..))")
	fun businessService() {}

	/**
	 * A data access operation is the execution of any method defined on a
	 * DAO interface. This definition assumes that interfaces are placed in the
	 * "dao" package, and that implementation types are in sub-packages.
	 */
	@Pointcut("execution(* com.xyz.dao.*.*(..))")
	fun dataAccessOperation() {}

}

你可以在需要点切割的地方参考此类定义的点割 通过引用该类的全限定名称与@Pointcut方法的名字。例如,要让服务层成为事务性,你 可以写出以下内容,引用com.xyz.CommonPointcuts.businessService() 命名为Pointcutspring-doc.cadn.net.cn

<aop:config>
	<aop:advisor
		pointcut="com.xyz.CommonPointcuts.businessService()"
		advice-ref="tx-advice"/>
</aop:config>

<tx:advice id="tx-advice">
	<tx:attributes>
		<tx:method name="*" propagation="REQUIRED"/>
	</tx:attributes>
</tx:advice>

<aop:config><aop:advisor>元素在基于模式的AOP支持中进行了讨论。这 事务元素在事务管理中讨论。spring-doc.cadn.net.cn

例子

春季AOP用户很可能会使用执行最常用的是Pointcut的指示器。 执行表达式的格式如下:spring-doc.cadn.net.cn

execution(modifiers-pattern?
			ret-type-pattern
			declaring-type-pattern?name-pattern(param-pattern)
			throws-pattern?)

除了返回类型的模式外的所有部分(RET-类型-模式在前面的片段中), 名称模式和参数模式是可选的。返回类型模式确定 方法的返回类型必须是什么,才能匹配连接点。 最常用作返回类型的模式。它匹配任何回馈 类型。只有当方法返回给定的 类型。名称模式与方法名称相匹配。你可以用万能符表示为全部或 这是名字模式的一部分。如果你指定一个宣告类型模式, 包含尾部**.将其连接到名称模式组件。 参数模式稍微复杂一些:匹配于 该方法不取参数,而()(..)匹配任意数量(零或更多)的参数。 该模式与取任意类型一个参数的方法相匹配。(*)(*,弦)匹配一个需要两个参数的方法。第一个可以是任意类型的,而 第二必须是字符串.请参考语言 更多信息请参见 AspectJ 编程指南的语义部分。spring-doc.cadn.net.cn

以下示例展示了一些常见的点割表达式:spring-doc.cadn.net.cn

  • 任何公共方法的执行:spring-doc.cadn.net.cn

    execution(public * *(..))
  • 任何名称开头为 的方法的执行设置:spring-doc.cadn.net.cn

    execution(* set*(..))
  • 会计服务接口:spring-doc.cadn.net.cn

    execution(* com.xyz.service.AccountService.*(..))
  • 服务包:spring-doc.cadn.net.cn

    execution(* com.xyz.service.*.*(..))
  • 在服务包或其子包中定义的任何方法的执行:spring-doc.cadn.net.cn

    execution(* com.xyz.service..*.*(..))
  • 服务包内的任何连接点(仅在 Spring AOP 中执行方法):spring-doc.cadn.net.cn

    within(com.xyz.service.*)
  • 服务包内的任何连接点(仅在 Spring AOP 中执行方法)或其其中一个 子软件包:spring-doc.cadn.net.cn

    within(com.xyz.service..*)
  • 任何连接点(仅在 Spring AOP 中执行方法)代理实现会计服务接口:spring-doc.cadn.net.cn

    this(com.xyz.service.AccountService)
    更常以装订形式使用。请参阅“声明建议”部分,了解如何在建议正文中使代理对象可用。
  • 任何连接点(仅在 Spring AOP 中执行方法)目标对象 实现会计服务接口:spring-doc.cadn.net.cn

    target(com.xyz.service.AccountService)
    目标更常以装订形式使用。详见“申报建议”部分 如何让目标对象在建议文中可用。
  • 任何只在 Spring AOP 中执行方法的连接点,只需一个参数 其中运行时传递的参数为序列 化:spring-doc.cadn.net.cn

    args(java.io.Serializable)
    args更常以装订形式使用。详见“申报建议”部分 关于如何在建议正文中提供方法论证。

    注意,本例中给出的切点不同于执行(* *(java.io.Serializable)).如果运行时传递的参数为序列 化,执行版本匹配,若方法签名声明单个 参数类型序列 化.spring-doc.cadn.net.cn

  • 任何连接点(仅在 Spring AOP 中执行方法)目标对象具有@Transactional注解:spring-doc.cadn.net.cn

    @target(org.springframework.transaction.annotation.Transactional)
    你也可以使用@target以约束形式。详见“申报建议”部分 如何在建议正文中使注释对象可用。
  • 任何连接点(仅在 Spring AOP 中执行方法)声明的类型 目标对象具有@Transactional注解:spring-doc.cadn.net.cn

    @within(org.springframework.transaction.annotation.Transactional)
    你也可以使用@within以约束形式。详见“申报建议”部分 如何在建议正文中使注释对象可用。
  • 任何连接点(仅在 Spring AOP 中执行方法)执行方法具有@Transactional注解:spring-doc.cadn.net.cn

    @annotation(org.springframework.transaction.annotation.Transactional)
    你也可以使用@annotation以约束形式。详见“申报建议”部分 关于如何使注释对象在建议正文中可用。
  • 任何连接点(仅在 Spring AOP 中执行方法)且只使用单一参数, 其中传递参数的运行时类型具有@Classified注解:spring-doc.cadn.net.cn

    @args(com.xyz.security.Classified)
    你也可以使用@args以约束形式。详见“申报建议”部分 如何在建议主体中使注释对象可用。
  • 在名为 Spring Bean 的 Spring Bean 上,任何连接点(仅在 Spring AOP 中执行方法)贸易服务:spring-doc.cadn.net.cn

    bean(tradeService)
  • Spring Beans 上任何连接点(仅在 Spring AOP 中执行方法)具有 匹配万用词表达式*服务:spring-doc.cadn.net.cn

    bean(*Service)

写出优秀的点切

编译过程中,AspectJ 处理点切以优化匹配 性能。检查代码并确定每个连接点是否匹配(静态或 动态上)给定的点割是一个代价高昂的过程。(动态匹配指匹配 无法通过静态分析完全确定,且在代码中放置测试 在代码运行时判断是否存在实际匹配)。第一次遇到 点切割声明,AspectJ将其重写为匹配的最优形式 过程。这意味着什么?基本上,点割会被重写成DNF(析取式) 法式)和点割的分量被排序为 那些评估成本较低的保险会先被检查。这意味着你无需担心 关于理解各种点切割指示器的性能,并可能提供它们 在点切声明中,顺序不限。spring-doc.cadn.net.cn

然而,AspectJ只能根据被告知工作。为了实现 匹配时,你应该考虑你想要达到什么目标,并缩小搜索范围 定义中尽可能匹配的空间。现有的标识 自然地分为三类:类型型、范围型和情境型:spring-doc.cadn.net.cn

  • 类型标识符选择特定类型的连接点:执行,获取,设置,处理器.spring-doc.cadn.net.cn

  • 界定标识符选择一组连接兴趣点 (可能有很多种):代码内spring-doc.cadn.net.cn

  • 上下文标识符根据上下文匹配(并可选择绑定):,目标@annotationspring-doc.cadn.net.cn

一个写得好的点割应至少包含前两种类型(类和 范围分析)。你可以包含上下文标识,以匹配 连接点上下文或绑定该上下文以便用于建议。仅提供 类式指称或仅使用上下文指称可行,但可能影响织造 性能(耗时和内存),由于额外的处理和分析。范围 指示符匹配非常快,使用它们意味着AspectJ能非常快速地匹配 驳回不应继续处理的连接点组。一个好 如果可能,Pointcut 应该始终包含一个。spring-doc.cadn.net.cn