【问题标题】:Why does Spring AOP intercept protected methods under certain circumstances?为什么Spring AOP在某些情况下会拦截受保护的方法?
【发布时间】:2017-03-16 11:40:29
【问题描述】:

我读到 Spring AOP 无法拦截私有和受保护的方法,但它以一种奇怪的方式拦截它们,为什么会这样?

我有这些函数要拦截:

public String getName(String string) {
   System.out.println("Name : " + name + string);
   return name;
}

protected String getNamesprotected(String string) {
  System.out.println("Name : " + name + string);
  return name;
}

这是我的@Aspect 代码:

@Aspect
public class Logging {

    @Before("execution(* com.tutorialspoint.Student.*Name*(..))")
    public void beforeAdvice(JoinPoint joinPoint){
       System.out.println("Going to setup student profile."+joinPoint.getSignature().toString());
    }
}

执行此代码时,getName 和 getNamesprotected 都会被拦截,但当我执行此代码时:

@Aspect
public class Logging {

    @Before("execution(* com.tutorialspoint.Student.getNamesprotected(..))")
    public void beforeAdvice1(JoinPoint joinPoint){
       System.out.println("Going to setup student profile."+joinPoint.getSignature().toString());
    }
}

然后什么都不会被截获。我也尝试用*getNamesprotected* 替换getNamesprotected,但它仍然没有拦截。它仅在*Name* 存在时拦截。

谁能解释一下为什么会这样?

【问题讨论】:

  • 除非您使用 AspectJ 而不是 Spring AOP,否则您所描述的很难相信。我只是觉得你犯了一个错误。 Spring AOP 永远不会拦截受保护的方法。如果您仍然认为是这样,请在 GitHub 上使用 SSCCE 证明这一点。那我愿意去看看。
  • 你能举一个SSCCE的例子吗?我是新来的,所以不完全知道如何创建。

标签: spring aop aspectj spring-aop


【解决方案1】:

由于 OP (Prateek Gupta) 似乎无法(相当不愿意)创建一点 SSCCE 来重现该问题,而且我只是在茶歇时感到无聊,所以我很快就用 Spring Boot 自己创建了一个,并且非常令人惊讶的是,Spring AOP 确实与文档相矛盾,至少在某些情况下,当涉及 CGLIB 代理时,它与受保护的方法相匹配。

因此,我为自己注册了一个 Spring 的 Jira 问题跟踪器帐户,并将此回归报告为 SPR-15354。如果对 Spring 开发团队的回答感兴趣,您可能需要订阅该票证的更新。


更新:回复我的票的人告诉我这是一个文档问题。正如 2006 年的 SPR-1611 告诉我们的那样,这已经在 Spring 1.2.7 中有意更改,但从未在文档中找到。底线:可以通过 Spring AOP 捕获受保护的方法,这不是偶然的,但已经 12 年没有记录了。


更新 2: 更新的文档文本将在下一个 Spring 版本中发布。今天想看固定文,引用在SPR-1611

【讨论】:

  • 感谢您的回答。澄清一下,我并不懒惰,只是我是这个行业的新手,现在还没有毕业。我以前没有使用过 GitHub,也没有使用过 StackOverflow。这是我人生中第一次在一个行业工作(实习1个月)。我确实阅读了有关 SSCCE 的手册并理解它是什么,但由于我不了解 GitHub,我无法创建一个,这就是我要求提供样本的原因,以便我至少可以了解它是如何完成的。跨度>
  • 亲爱的 Prateek,对于行业或 StackOverflow 的新手来说,在创建一个能够重现您的问题的、减少到最小的、独立的小示例方面有何障碍?我看不到那个。抱歉,但是如果您的代码中有可重现的问题,您还应该能够从您的大项目中提取它的最小版本到一个较小的项目中。你不需要毕业才能做到这一点。能够将您的代码签入 Git 存储库是一项基本的开发技能,没有它,任何开发人员如何生存?一天就能学会。
  • 我刚刚用新的工单状态和解释更新了我的答案。
  • 如果受保护的 Spring AOP 可以捕获,那么为什么当我给出完整的方法名称时它没有被捕获?
  • 我没有足够的信息来回答,因为您只提供了 sn-ps,而不是 MCVE。所以我只能推测你的切入点可能有错字。也许包名是错误的,也许getNamesprotected实际上是getNamesProtected,大写的“P”。对我来说,无论我尝试哪种变体,完整的方法名称或*,它都有效。这一次由你来修复你自己的程序。祝你好运,我们的讨论到此结束。
【解决方案2】:

谁能解释一下为什么会这样?

由于 Spring 的 AOP 框架基于代理的性质,根据定义,受保护的方法不会被拦截,对于 JDK 代理(如果不适用)和 CGLIB 代理(这在技术上可行但不推荐用于 AOP目的)。

因此,任何给定的切入点都将仅与公共方法匹配!

如果您的拦截需求包括受保护/私有方法甚至构造函数,请考虑使用 Spring 驱动的原生 AspectJ 编织,而不是 Spring 的基于代理的 AOP 框架。

执行此代码时,getName 和 getNamesprotected 拦截

 @Before("execution(* com.tutorialspoint.Student.*Name*(..))")

这里前面的通配符匹配带有任何修饰符(public、protected 和 private)和任何返回类型的方法。参数列表中的两个点匹配任意数量的参数。

试试这个它应该执行你的受保护方法

@Pointcut("execution(protected * *.*(..))")

如果它适合你,你也可以试试这个(我不是 100% 确定)

 @Before("execution(* com.tutorialspoint.Student+.getNamesprotected(..))")

【讨论】:

  • 虽然你说的都是正确的,但它并没有回答 OP 的原始问题。
  • @Pointcut("execution(protected * *.*(..))")@Before("execution(* com.tutorialspoint.Student+.getNamesprotected(..))") 都没有拦截受保护的方法,只有我的问题中的 *Name* 正在拦截受保护的方法,因为我使用的是 Spring AOP,所以理想情况下不应该发生这种情况。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
  • 2018-01-31
  • 2021-11-01
  • 2021-11-06
相关资源
最近更新 更多