我正在学习面向方面的编程概念和Spring AOP。我无法理解切入点和连接点之间的区别-对我来说,两者似乎是相同的。Pointcut是您应用建议的地方,Joinpoint也是我们可以应用建议的地方。那有什么区别呢?
切入点的示例可以是:
@Pointcut("execution(* * getName()")
联接点的示例可以是什么?
我正在学习面向方面的编程概念和Spring AOP。我无法理解切入点和连接点之间的区别-对我来说,两者似乎是相同的。Pointcut是您应用建议的地方,Joinpoint也是我们可以应用建议的地方。那有什么区别呢?
切入点的示例可以是:
@Pointcut("execution(* * getName()")
联接点的示例可以是什么?
Answers:
连接点:连接点是应用程序的程序执行中可以插入方面的候选点。此点可以是调用方法,引发异常或甚至修改字段。这些是您的方面的代码可以插入到应用程序的常规流程中以添加新行为的要点。
忠告:这是一个对象,其中包括对系统范围内关注点的API调用,这些关注点表示要在点指定的连接点处执行的操作。
切入点:切入点定义了应在哪些连接点处应用关联的建议。可以在AOP框架支持的任何连接点上应用建议。当然,您不想在所有可能的连接点上应用所有方面。切入点允许您指定要在何处应用建议。通常,您使用显式的类和方法名称或通过定义匹配的类和方法名称模式的正则表达式来指定这些切入点。某些AOP框架允许您创建动态切入点,这些切入点可根据运行时决策(例如方法参数的值)确定是否应用建议。
下图可以帮助您了解建议,PointCut,Joinpoints。
使用餐厅类比的解释: @Victor提供
当您去餐厅时,您会看到一个菜单,并看到几个可供选择的选项。您可以订购菜单上的任何一项或多项。但是,除非您实际订购它们,否则它们只是“用餐的机会”。一旦您下了订单,服务员就将它带到了桌上,就成了一顿饭。
连接点是菜单上的选项,“切入点”是您选择的项。
连接点是代码中供您应用方面的机会……这只是机会。抓住这个机会并选择一个或多个Joinpoint并将其应用到一个方面后,您便有了一个Pointcut。
来源Wiki:
一个连接点是一个程序,控制流可以通过到达的控制流程的一个点两个不同的路径(IMO:这就是为什么叫关节)。
建议描述了一类可修改其他功能的功能
一个切入点是一组连接点。
more Joinpoints and apply an aspect to them, you've got a Pointcut.
对他们的方面还是对他们的建议?
要了解连接点和切入点之间的区别,可以将切入点视为指定编织规则,并将连接点视为满足这些规则的情况。
在下面的示例中,
@Pointcut("execution(* * getName()")
切入点定义了规则,说,建议应应用于任何包中任何类中存在的getName()方法,而连接点将是类中存在的所有getName()方法的列表,以便可以将建议应用于这些方法。
(对于Spring,Rule仅适用于托管Bean,建议仅适用于公共方法)。
JoinPoints:这些基本上是实际业务逻辑中的位置,您希望在其中插入一些必需的功能,但这些功能不是实际业务逻辑的一部分。JoinPint的一些示例包括:方法调用,方法正常返回,方法引发异常,实例化对象,引用对象等。
切入点:切入点类似于正则表达式,用于标识连接点。Pontcuts使用“切入点表达语言”表示。切入点是执行流程中需要应用横切关注点的点。Joinpoint和Pointcut之间是有区别的。连接点更通用,表示我们可以“选择”引入交叉关注点的任何控制流,而切入点标识了“我们希望”引入交叉关注点的此类连接点。
Layman对AOP概念的新手的解释。这不是穷举性的,但应该有助于理解这些概念。如果您已经熟悉基本术语,则可以立即停止阅读。
假设您有一个普通的Employee类,并且您想在每次调用这些方法时执行一些操作。
class Employee{
public String getName(int id){....}
private int getID(String name){...}
}
这些方法称为JoinPoints。我们需要一种识别这些方法的方法,以便框架可以在已加载的所有类。方法中找到这些方法。因此,我们将编写一个正则表达式来匹配这些方法的签名。尽管您将在下面看到更多内容,但是松散地定义了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>
根据文档:
连接点:程序执行过程中的一个点,例如方法执行或异常处理。
您可以将关节点视为程序执行中的事件。如果您使用的是Spring AOP,那么这甚至仅限于方法的调用。AspectJ提供了更大的灵活性。
但是您永远不会处理所有事件,因为去餐馆时您不会吃菜单上的所有食物(我可能不认识您,您可能会!但是,我当然不会)。因此,您可以选择要处理的事件以及如何处理它们。切入点在这里。根据文档,
切入点:与连接点匹配的谓词。
然后你联想做什么用的切入点,有云咨询。根据文档,
建议与切入点表达式关联,并在与该切入点匹配的任何连接点处运行。
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()
是在我们的切点与关节点匹配之后将执行的建议somePointCut
doYourBusiness()
beforeSomePointCut()
也是与所有方法执行相匹配的建议public
。不像afterSomePointCut
,这使用了一个内联切点声明如果您不相信我,可以查看文档。我希望这有帮助
两者都属于面向方面编程的“何处”。
连接点是一个单独的位置,您可以在其中使用AOP执行代码。例如,“当方法抛出异常时”。
切入点是连接点的集合。例如,“当类Foo中的方法引发异常时”。
JoinPoint:Joinpoint是程序执行中的点,执行流发生了变化,例如异常捕获,调用其他方法。
PointCut:PointCut基本上是那些可以在其中放置建议(或调用方面)的联接点。
因此,基本上,PointCuts是JoinPoints的子集。
春季的AOP中有{顾问,建议,切入点,连接点}
如您所知,aop的主要目的是将跨领域关注逻辑(Aspect)与应用程序代码分离,为了在Spring中实现这一点,我们使用(Advice / Advisor)
Pointcut用于过滤我们要确切应用此建议的位置,例如“所有方法均以insert开头”,因此将排除其他方法,这就是我们在Pointcut接口{ClassFilter和MethodMatcher}中使用的原因
因此,Advice是跨部门逻辑实现,Advisor是建议加上PointCut,如果仅使用通知,则spring会将其映射到Advisor并使切入点为TRUE,这意味着不要阻塞任何内容。这就是为什么当您仅使用建议时,它会应用到目标类的所有方法的原因,因为您没有过滤它们。
但是Joinpoint是程序中的一个位置,您可以在访问Class对象时像反射一样思考它,然后可以获取Method对象,然后可以调用此类中的任何方法,这就是编译器的工作原理,如果您认为这可以想像联接点。
Joinpoint可以与字段,构造函数或方法一起使用,但是在Spring中,我们仅具有方法的连接点,这就是为什么在Spring中,我们具有(之前,之后,抛出,周围)类型的Joinpoint,它们都引用类中的位置。
正如我提到的那样,您可以在没有切入点(没有过滤器)的情况下获得建议,那么它将被应用于所有方法,或者您可以拥有将[advice + pointcut]应用于特定方法的顾问,但是如果没有这些建议,您将无法得到建议像切入点这样的连接点,必须指定它,这就是为什么spring中的建议类型与连接点类型完全相同的原因,因此,当您选择建议时,您会隐式选择哪个连接点。
总结起来,建议是目标类的方面的实现逻辑,该建议应该具有一个连接点,如调用之前,调用之后,引发之后或周围调用,然后可以使用切入点来过滤要应用它的确切位置过滤方法或没有切入点(没有过滤器),因此它将应用于类的所有方法。
在Aspect-类实现上定义了一个切入点。切入点基本上是指建议中的切入点表达。
例如
@Before("execution(* app.purchase2.service.impl.*(..))")
public void includeAddOns(RolesAllowed roles) {
..
}
上面的意思是,在调用任何方法之前(由于@Before的建议)(在包“ app.purchase2.service.impl”中的类中),将调用“ includeAddOns”方法
整个注释称为切入点
@Before("execution(* app.purchase2.service.impl.*(..))")
结合点是实际的方法调用,将程序包“ app.purchase2.service.impl”中的方法与方面类“ includeAddOns()”中的方法结合在一起。
您可以使用org.aspectj.lang.JoinPoint
类访问连接点的属性。