Spring AOP:JoinPoint 和 PointCut 有啥区别?
Posted
技术标签:
【中文标题】Spring AOP:JoinPoint 和 PointCut 有啥区别?【英文标题】:Spring AOP: What's the difference between JoinPoint and PointCut?Spring AOP:JoinPoint 和 PointCut 有什么区别? 【发布时间】:2013-03-05 01:15:33 【问题描述】:我正在学习面向方面的编程概念和 Spring AOP。我无法理解切入点和连接点之间的区别——它们对我来说似乎都是一样的。切入点是您应用建议的地方,而连接点也是我们可以应用建议的地方。那有什么区别呢?
切入点的示例可以是:
@Pointcut("execution(* * getName()")
什么是连接点的示例?
【问题讨论】:
【参考方案1】:两者都与面向方面编程的“位置”有关。
连接点是您可以使用 AOP 执行代码的单独位置。例如。 “当方法抛出异常时”。
切入点是连接点的集合。例如。 “当 Foo 类中的方法抛出异常时”。
【讨论】:
【参考方案2】:将 AOP 语言(如 AspectJ)与数据查询语言(如 SQL)进行比较,
您可以将连接点(即您的代码中您可以编织方面代码的所有位置)视为一个包含许多行的数据库表。 切入点类似于 SELECT 语句,可以选择用户定义的行/连接点子集。 您编入这些选定位置的实际代码称为advice。【讨论】:
【参考方案3】:要了解连接点和切入点之间的区别,请考虑切入点 将编织规则和连接点指定为满足这些规则的情况。
在下面的例子中,
@Pointcut("execution(* * getName()")
Pointcut 定义规则说,建议应该应用于任何包中任何类中存在的 getName() 方法,并且连接点将是类中存在的所有 getName() 方法的列表,以便可以将建议应用于这些方法。
(在 Spring 的情况下,规则将仅应用于托管 bean,建议只能应用于公共方法)。
【讨论】:
"Pointcut 定义规则说,建议应该应用于任何包中任何类中存在的 getName() 方法,并且连接点将是类中存在的所有 getName() 方法的列表,以便建议可以应用于这些方法。”我很抱歉,但这越来越令人困惑。你能给我一个现实世界日常生活场景中的类比吗?【参考方案4】:我同意 mgroves.. 一个切点可以被认为是多个关节点的集合。关节点指定可以实施建议的特定位置,其中切入点反映了所有关节点的列表。
【讨论】:
【参考方案5】:JoinPoints:这些基本上是实际业务逻辑中的位置,您希望在其中插入一些必要但不属于实际业务逻辑的杂项功能。 JoinPints 的一些示例是:方法调用、方法正常返回、方法抛出异常、实例化对象、引用对象等...
切入点:切入点类似于用于识别连接点的正则表达式。使用“切入点表达语言”来表达切点。切入点是需要应用横切关注点的执行流程点。 Joinpoint 和 Pointcut 是有区别的;连接点更通用,表示我们“可能选择”引入横切关注点的任何控制流,而切入点识别“我们想要”引入横切关注点的连接点。
【讨论】:
Joinpoint - 应用/运行建议代码的潜在位置。切入点 - 实际选择的执行建议的连接点。【参考方案6】:JoinPoint:它指定应用程序中将执行 Advice 的点(方法)。
切入点:它是JoinPoints的组合,它指定了JoinPoint Advice的执行位置。
【讨论】:
【参考方案7】:春季的AOP有Advisor, Advice, Pointcut, Joinpoint
如您所知,aop 的主要目的是将横切关注点逻辑(Aspect)从应用程序代码中解耦,为了在 Spring 中实现这一点,我们使用(Advice/Advisor)
Pointcut 用于过滤我们想要准确应用此建议的位置,例如“所有方法都以 insert 开头”,因此将排除其他方法,这就是我们在 Pointcut 接口 ClassFilter and MethodMatcher 中使用的原因
所以 Advice 是横切逻辑实现,Advisor 是建议加上切入点,如果您只使用建议,spring 会将其映射到顾问并使切入点为 TRUE,这意味着不要阻塞任何东西。这就是为什么当您只使用建议时,它会应用于目标类的所有方法,因为您没有过滤它们。
但是Joinpoint是程序中的一个位置,你可以把它想象成反射,当你访问Class对象然后你可以得到Method对象,然后你可以调用这个类中的任何方法,这就是编译器的工作方式,如果你这样想你就可以想象Joinpoint了。
Joinpoint 可以是字段、构造函数或方法,但在 Spring 中我们只有带有方法的 joinpoint,这就是为什么在 Spring 中我们有 (Before、After、Throws、Around) 类型的 Joinpoint,它们都指类中的位置.
正如我所提到的,您可以有没有切入点(无过滤器)的建议,然后它将应用于所有方法,或者您可以拥有 [advice + pointcut] 顾问,它将应用于特定方法,但您不能有没有像切入点这样的连接点的建议,你必须指定它,这就是为什么 spring 中的建议类型与连接点的类型完全相同,所以当你选择一个建议时,你会隐式选择哪个连接点。
总而言之,advice 是你的 aspect 到目标类的实现逻辑,这个advice 应该有一个连接点,比如在调用之前、调用之后、抛出之后或调用周围,然后你可以过滤你想要应用它的确切位置使用切入点过滤方法或不使用切入点(无过滤器),以便将其应用于类的所有方法。
【讨论】:
【参考方案8】:Joinpoint:joinpoint 是应用程序程序执行中的一个候选点,可以插入一个方面。这个点可以是被调用的方法,被抛出的异常,甚至是被修改的字段。这些是可以将方面的代码插入到应用程序的正常流程中以添加新行为的点。
建议:这是一个对象,其中包括对系统范围内关注点的 API 调用,表示要在由点指定的连接点处执行的操作。
切入点:切入点定义应在哪些连接点应用相关的 Advice。建议可以应用于 AOP 框架支持的任何连接点。当然,您不想在所有可能的连接点上应用所有方面。切入点允许您指定希望应用建议的位置。通常,您使用显式的类和方法名称或通过定义匹配的类和方法名称模式的正则表达式来指定这些切入点。一些 AOP 框架允许您创建动态切入点,以确定是否根据运行时决策应用建议,例如方法参数的值。
下图可以帮助你理解Advice、PointCut、Joinpoints。
Source
餐厅类比解释: Source by @Victor
当您去餐厅时,您会查看菜单并看到几个可供选择的选项。您可以订购菜单上的任何一项或多项。但在您真正订购之前,它们只是“用餐机会”。一旦你下单,服务员就会把它送到你的餐桌上,这就是一顿饭。
连接点是菜单上的选项,切入点是您选择的项目。
Joinpoint 是代码中的一个机会,您可以应用一个方面……只是一个机会。一旦您抓住这个机会并选择一个或多个连接点并将一个方面应用于它们,您就获得了一个切入点。
来源Wiki:
Joinpoint 是程序控制流中的一个点,其中 控制流可以通过两条不同的路径(IMO:这就是为什么调用 联合)。
Advice描述了修改其他函数的一类函数
Pointcut 是 Joinpoint 的匹配 Pattern,即连接点的集合。
【讨论】:
这应该被标记为正确答案。只是要添加更多信息,请查看 Cragi Walls 答案...coderanch.com/t/485525/Spring/Difference-Joint-Point-Point-Cut。 重点:切入点定义了应在哪些连接点应用建议 +1 只是为了确认,more Joinpoints and apply an aspect to them, you've got a Pointcut.
对他们的看法或对他们的建议?
@Premraj 所以,根据你的类比建议将是点餐。我说的对吗?
餐厅类比有助于消除 JoinPoints 和切入点之间的混淆,谢谢!【参考方案9】:
连接点是我们实际放置建议的地方
但切点是连接点的集合。也就是说我们把横切逻辑有多少种方式叫做切入点
【讨论】:
【参考方案10】:JoinPoint:JoinPoint 是程序执行中执行流程发生变化的点,例如异常捕获、调用其他方法。
PointCut:PointCut 基本上是那些您可以放置建议(或调用方面)的连接点。
所以基本上 PointCuts 是 JoinPoints 的子集。
【讨论】:
【参考方案11】:切入点是在 Aspect - 类实现上定义的。切入点基本上是指建议中的切入点表达式。
例如,
@Before("execution(* app.purchase2.service.impl.*(..))")
public void includeAddOns(RolesAllowed roles)
..
上面的意思是,“includeAddOns”方法在调用之前被调用(由于@Before建议)任何方法(在包“app.purchase2.service.impl”中的类中)
整个注解称为切入点
@Before("execution(* app.purchase2.service.impl.*(..))")
联合点是实际的方法调用,它将包“app.purchase2.service.impl”中的方法连接到方面类“includeAddOns()”中的方法。
您可以使用org.aspectj.lang.JoinPoint
类访问连接点的属性。
【讨论】:
好答案!我终于明白了其中的区别!【参考方案12】:为刚接触 AOP 概念的人提供的通俗解释。这并不详尽,但应该有助于掌握这些概念。如果您已经熟悉基本术语,现在可以停止阅读。
假设您有一个普通的 Employee 类,并且您想在每次调用这些方法时执行一些操作。
class Employee
public String getName(int id)....
private int getID(String name)...
这些方法称为JoinPoints。我们需要一种方法来识别这些方法,以便框架可以在它已加载的所有 classes.methods 中找到这些方法。 所以我们将编写一个正则表达式来匹配这些方法的签名。虽然您将在下面看到更多内容,但这个正则表达式松散地定义了 Pointcut。例如
* * mypackage.Employee.get*(*)
第一个 * 用于修饰符 public/private/protected/default。 第二个 * 表示方法的返回类型。
但是你还需要说两件事:
-
何时应该采取行动 -
例如,方法执行之前/之后或异常
匹配时应该做什么(可能只是打印一条消息)
这两者的组合称为建议。
您可以想象,您必须编写一个函数才能执行 #2。所以这就是基础知识的样子。
注意:为清楚起见,使用单词 REGEX 代替 * * mypackage.Employee.get*(*)
。实际上,完整的表达式进入了定义。
@Before("execution(REGEX)")
public void doBeforeLogging() .... <-- executed before the matching-method is called
@After("execution(REGEX)")
public void doAfterLogging() .... <-- executed after the matching-method is called
一旦你开始大量使用这些,你最终可能会指定许多@After/@Before/@Around 建议。 重复正则表达式最终会使事情变得混乱和难以维护。 因此,我们所做的只是为表达式命名,然后在 Aspect 类的其他任何地方使用它。
@Pointcut("execution(REGEX)") <-- Note the introduction of Pointcut keyword
public void allGetterLogging() <-- This is usually empty
@Before("allGetterLogging")
public void doBeforeLogging() ....
@After("allGetterLogging")
public void doAfterLogging() ....
顺便说一句,您还希望将整个逻辑包装在一个名为 Aspect 的类中,然后您将编写一个类:
@Aspect
public class MyAwesomeAspect....
要让所有这些工作正常工作,您必须告诉 Spring 解析类以读取、理解和对 @AOP 关键字采取行动。一种方法是在 spring config xml 文件中指定以下内容:
<aop:aspectj-autoproxy>
【讨论】:
我是 AOP 新手,这个解释帮助我非常清楚地理解了 Advice/Pointcuts/JoinPoints 之间的关系。 先生,这对新手来说是一个更好的解释。谢谢【参考方案13】:定义
根据文档:
加入点:程序执行过程中的一个点,例如 方法的执行或异常的处理。
您可以将联合点视为程序执行中的事件。如果您使用的是 Spring AOP,这甚至仅限于方法的调用。 AspectJ 提供了更大的灵活性。
但是你永远不会处理所有事件,因为你去餐厅时不会吃掉菜单上的所有食物(我不认识你,你可能会!但是,我当然不知道)。因此,您可以选择要处理的事件以及如何处理它们。 切入点。根据文档,
切入点:匹配连接点的谓词。
然后你将要做什么与切入点联系起来,就会出现建议。根据文档,
Advice 与 切入点 表达式相关联,并在与切入点匹配的任何连接点处运行。
代码
package com.amanu.example;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author Amanuel Nega on 10/25/16.
*/
class ExampleBussinessClass
public Object doYourBusiness()
return new Object();
@Aspect
class SomeAspect
@Pointcut("execution(* com.amanu.example.ExampleBussinessClass.doYourBusiness())")
public void somePointCut()
//Empty body suffices
@After("somePointCut()")
public void afterSomePointCut()
//Do what you want to do after the joint point is executed
@Before("execution(* *(*))")
public void beforeSomePointCut()
//Do what you want to do before the joint point is executed
代码说明
ExampleBusinessClass
被代理后,是我们的目标!
doYourBusiness()
是一个可能的联合点
SomeAspect
是我们涉及多个关注点的方面,例如 ExampleBusinessClass
somePointCut()
是一个与我们的关节点相匹配的切入点的定义
afterSomePointCut()
是一个 advice,将在我们的 somePointCut
切入点 匹配 doYourBusiness()
joint point 之后执行
beforeSomePointCut()
也是一个匹配所有public
方法执行的advice。与afterSomePointCut
不同,这个使用了内联切点声明
如果你不相信我,你可以看看documentation。我希望这会有所帮助
【讨论】:
简单解释。只有三个引用的文本足以理解。谢谢。【参考方案14】:PointCut 是一个注解,您可以在()
内声明适用建议的范围。
相反,JoinPoint 是一个接口,它是用于所有五个建议的参数。特别是对于@Around通知,应用了ProceedingJoinPoint(JoinPoint的子接口),它提供了.proceed()
方法。所以你可以控制是否让程序继续进行。你也可以改变它的参数。
【讨论】:
以上是关于Spring AOP:JoinPoint 和 PointCut 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章