Spring AOP:JoinPoint和PointCut有什么区别?

Spring AOP: What's the difference between JoinPoint and PointCut?

我正在学习面向方面的编程概念和Spring AOP。 我无法理解切入点和连接点之间的区别-对我来说,它们似乎都是相同的。 Pointcut是您应用建议的地方,Joinpoint也是我们可以应用建议的地方。 那有什么区别呢?

切入点的示例可以是:

1
@Pointcut("execution(* * getName()")

联接点的示例可以是什么?


连接点:连接点是应用程序的程序执行中可以插入方面的候选点。此点可以是调用方法,引发异常或甚至修改字段。在这些方面,您可以将方面的代码插入应用程序的常规流程中以添加新行为。

忠告:这是一个对象,其中包括对系统范围内关注点的API调用,这些关注点表示要在由点指定的连接点处执行的操作。

切入点:切入点定义了应在哪些连接点处应用关联的建议。可以在AOP框架支持的任何连接点上应用建议。当然,您不想在所有可能的连接点上应用所有方面。切入点允许您指定要在何处应用建议。通常,您使用显式的类和方法名称或通过定义匹配的类和方法名称模式的正则表达式来指定这些切入点。某些AOP框架允许您创建动态切入点,这些切入点可根据运行时决策(例如方法参数的值)确定是否应用建议。

下图可以帮助您了解建议,PointCut,Joinpoints。
enter image description here

资源

使用餐厅类比的解释:@Victor提供

当您去餐厅时,您会看到一个菜单,并看到几个选项可供选择。您可以订购菜单上的任何一项或多项。但是,除非您实际订购它们,否则它们只是"用餐的机会"。一旦您下了订单,服务员就将它带到了桌上,就成了一顿饭。

连接点是菜单上的选项,切入点是您选择的项。

连接点是代码中供您应用方面的机会,这只是机会。抓住这个机会并选择一个或多个Joinpoint并将其应用到一个方面后,您便有了一个Pointcut。

来源Wiki:

A join point is a point in the control flow of a program where the
control flow can arrive via two different paths(IMO : that's why call
joint).

Advice describes a class of functions which modify other functions

A pointcut is a set of join points.


JoinPoints:这些基本上是实际业务逻辑中的位置,您希望在其中插入一些必需的功能,但这些功能不是实际业务逻辑的一部分。 JoinPint的一些示例包括:方法调用,方法正常返回,方法引发异常,实例化对象,引用对象等。

切入点:切入点类似于正则表达式,用于标识连接点。 Pontcuts使用"切入点表达语言"表示。切入点是执行流程中需要应用横切关注点的点。 Joinpoint和Pointcut之间是有区别的。连接点更通用,表示任何我们可以"选择"引入交叉关注点的控制流,而切入点则标识了"我们希望"引入交叉关注点的此类连接点。


要了解连接点和切入点之间的区别,请考虑切入点
指定编织规则和连接点作为满足这些规则的情况。

在下面的示例中,

1
  @Pointcut("execution(* * getName()")

切入点定义了规则,说,建议应应用于任何包中任何类中存在的getName()方法,而连接点将是类中存在的所有getName()方法的列表,以便可以将建议应用于这些方法。

(对于Spring,Rule仅适用于托管Bean,建议仅适用于公共方法)。


Layman对AOP概念的新手的解释。这不是穷举性的,但应有助于理解这些概念。如果您已经熟悉基本术语,则可以立即停止阅读。

假设您有一个普通的Employee类,并且您想在每次调用这些方法时执行一些操作。

1
2
3
4
class Employee{
    public String getName(int id){....}
    private int getID(String name){...}
}

这些方法称为JoinPoints。我们需要一种识别这些方法的方法,以便框架可以在已加载的所有类。方法中找到这些方法。
因此,我们将编写一个正则表达式来匹配这些方法的签名。尽管您将在下面看到更多内容,但是从广义上讲,此正则表达式定义了Pointcut。例如

1
* * mypackage.Employee.get*(*)

第一个*用于修饰符public / private / protected / default。
第二个*是方法的返回类型。

但是然后您还需要说两件事:

  • 什么时候应该采取行动-
    例如,在方法执行之前/之后或发生异常时
  • 匹配时该怎么办(也许只是打印一条消息)
  • 这两个的组合称为建议。

    如您所料,您将必须编写一个函数才能执行#2。所以这是基本的样子。

    注意:为清楚起见,请使用单词REGEX代替* * mypackage.Employee.get*(*)。实际上,完整的表达进入了定义。

    1
    2
    3
    4
    5
    @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类的其他地方使用它。

    1
    2
    3
    4
    5
    6
    7
    8
    @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的类中,并编写一个类:

    1
    2
    @Aspect
    public class MyAwesomeAspect{....}

    为了使所有这些东西都起作用,您必须告诉Spring解析类,以读取,理解@AOP关键字并采取措施。一种方法是在spring config xml文件中指定以下内容:


    将诸如AspectJ之类的AOP语言与诸如SQL之类的数据查询语言进行比较,您可以将连接点(即代码中可以编织方面代码的所有位置)视为具有许多行的数据库表。切入点就像SELECT角色一样,可以选择用户定义的行/联接点子集。您编织到这些选定位置中的实际代码称为建议。


    定义

    根据文档:

    Join point: a point during the execution of a program, such as the
    execution of a method or the handling of an exception.

    您可以将关节点视为程序执行中的事件。如果您使用的是Spring AOP,那么这甚至仅限于方法的调用。 AspectJ提供了更大的灵活性。

    但是您永远不会处理所有事件,因为去餐馆时您不会吃菜单上的所有食物(我可能不认识您,您可能会!但是,我当然不会)。因此,您可以选择要处理的事件以及如何处理它们。切入点在这里。根据文档,

    Pointcut: a predicate that matches join points.

    然后,您将与切入点关联的操作与建议联系在一起。根据文档,

    Advice is associated with a pointcut expression and runs at any join point matched by the pointcut.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    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的子集。


    在Aspect-类实现上定义了一个切入点。切入点基本上是指建议中的切入点表达式。

    例如

    1
    2
    3
    4
    @Before("execution(* app.purchase2.service.impl.*(..))")
    public void includeAddOns(RolesAllowed roles) {
    ..
    }

    上面的意思是,在调用任何方法之前(由于@Before建议),将调用" includeAddOns"方法(在包" app.purchase2.service.impl"中的类中)

    整个注释称为切入点
    @Before("execution(* app.purchase2.service.impl.*(..))")

    结合点是实际的方法调用,将程序包" app.purchase2.service.impl"中的方法与方面类" includeAddOns()"中的方法结合在一起。

    您可以使用org.aspectj.lang.JoinPoint类访问连接点的属性。


    我同意mgroves的观点。切点可以看作是多个联合点的集合。联合点指定可以实施建议的特定位置,因为切入点反映了所有联合点的列表。


    春季的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中的通知类型与连接点类型完全相同的原因,因此,当您选择建议时,会隐式选择哪个连接点。

    总结起来,建议是目标类的方面的实现逻辑,该建议应该具有一个连接点,如调用之前,调用之后,引发之后或周围调用,然后可以使用切入点过滤要应用它的确切位置过滤方法或没有切入点(没有过滤器),因此它将应用于类的所有方法。


    JoinPoint:它指定应用程序中将执行建议的点(方法)。

    切入点:这是JoinPoints的组合,它指定执行JoinPoint通知的位置。


    连接点是我们实际放置建议的地方

    但切入点是连接点的集合。这意味着我们如何配置横切逻辑的方法称为切点