如何制作切入点来指示子类的方法调用没有覆盖父类的方法?

问题描述 投票:0回答:1

只有一个接口

Foo
,有两个默认方法
m1
m2

有 3 个类

Foo1
Foo2
Foo3
实现
Foo
Foo3
不会覆盖方法
m1
,但
Foo1
Foo2
会覆盖方法。

我想创建一个针对

Foo3
m1
方法的方面。

我尝试了

@Pointcut("bean(foo3) && execution(* *.m1(..))
,并且在Spring Boot运行时它可以正常工作。但是当我以编程方式创建代理对象进行单元测试时,它不起作用。

我知道

bean(foo3)
使它可以在Spring Boot下工作,但是我找不到任何替代方法来表达切入点,它在测试中仍然有效。在这种情况下我怎样才能让它发挥作用?

public interface Foo {
    default Object m1() {
        // doSomething
        return Something;
    }

    default Object m2() {
        // doSomething
        return Something;
    }
}
public class Foo3 implements Foo {
    // not overriding any method.
}
@Component @Aspect
public class ExampleAspect {
    @Pointcut("bean(foo3) && execution(* *.m1(..))")
    public void exampleAspect() {}

    @Around("exampleAspect()")
    public Object proxyMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        // ...
        Object result = joinPoint.proceed();
        // ...
    }
}
public Foo3Test {
    Foo instance = new Foo3();
    AspectJProxyFactory factory = new AspectJProxyFactory(instance);
    factory.addAspect(new ExampleAspect());
    Foo proxy = factory.getProxy();
    proxy.m1(); // it didn't use proxy. invoke real method.
}

我尝试了这些切入点:

  • target(Foo3) && execution(* Foo.m1(..))
    即使在Spring Boot下也无法工作
  • within(Foo3) && execution(* Foo.m1(..))
    即使在Spring Boot下也无法工作
  • execution(Foo.m1(..))
    有效,但所有
    m1
    方法都被代理
spring-boot junit5 spring-aop
1个回答
0
投票

我不是 Spring 专家,但为了使特殊的 Spring AOP 切入点指示符

bean
工作,我想您在测试中可能需要一个应用程序上下文。然而,我理解无需所有仪式即可创建快速运行的测试的必要性。幸运的是,这并不难实现。只需将切入点更改为:

@Pointcut("target(Foo3) && execution(* m1(..))")
public void exampleAspect() {}

我试过了,效果很好。这是我测试的方法:

package de.scrum_master.spring.q76824399;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class ExampleAspect {
  @Pointcut("target(Foo3) && execution(* m1(..))")
  public void exampleAspect() {}

  @Around("exampleAspect()")
  public Object proxyMethod(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println(joinPoint + " -> " + joinPoint.getTarget());
    return joinPoint.proceed();
  }
}
package de.scrum_master.spring.q76824399;

import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;

public class Foo3Test {
  public static void main(String[] args) {
    ExampleAspect aspect = new ExampleAspect();
    Foo[] instances = { new Foo1(), new Foo2(), new Foo3() };
    for (Foo instance : instances) {
      AspectJProxyFactory factory = new AspectJProxyFactory(instance);
      factory.addAspect(aspect);
      Foo proxy = factory.getProxy();
      proxy.m1();
    }
  }
}

这是控制台日志:

10:45:11.823 [main] DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object de.scrum_master.spring.q76824399.ExampleAspect.proxyMethod(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
10:45:12.055 [main] DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object de.scrum_master.spring.q76824399.ExampleAspect.proxyMethod(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
10:45:12.071 [main] DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public java.lang.Object de.scrum_master.spring.q76824399.ExampleAspect.proxyMethod(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable
execution(Object de.scrum_master.spring.q76824399.Foo.m1()) -> de.scrum_master.spring.q76824399.Foo3@6eda5c9

请注意该方面如何找到

Foo1
Foo2
Foo3
的所有 3 个实例,但仅针对
Foo3
实例触发建议。

© www.soinside.com 2019 - 2024. All rights reserved.