当前位置: 首页 > 知识库问答 >
问题:

自定义注释的Spring AOP切入点无法在内部静态类中工作

栾峰
2023-03-14

目前,我有以下切入点。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    @Aspect
    @Component
    public static class MyAnnotationAspect {
        @Pointcut("execution(* (@com.test.MyAnnotation *).*(..))")
        public void methodInMyAnnotationType() {}

        @Around("methodInMyAnnotationType()")
        public Object annotate(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("AOP WORKING");
            return pjp.proceed();
        }
    }
}

当我在根级类上添加< code>@MyAnnotation时,它工作得很好,如下所示。

@MyAnnotation
@Service
public class ShiftModule {
    @Resource
    private ShiftModule self;

    /* Executing anything using self.method() triggers the Aspect
     * for @MyAnnotation perfectly
     */
}

如果我在内部静态类上添加注释,它也不起作用。

@Service
public class ShiftModule {
    @Service
    @MyAnnotation
    public class AnnotatedShiftModule extends ShiftModule {}

    @Resource
    private AnnotatedShiftModule self;

    /* Executing anything using self.method() does NOT trigger the 
     * Aspect for @MyAnnotation or even framework's annotations
     * like @Async
     */
}

如果我在接口上使用此技术,它就可以工作。

@Repository
public interface OrderRepo extends JpaRepository<Order,Long> {
    @Repository("annotatedOrderRepo")
    @MyAnnotation
    public interface AnnotatedOrderRepo extends OrderRepo {}
}

如果你能告诉我如何使用类和春豆来实现它,我将非常感激。

共有2个答案

毛越
2023-03-14
匿名用户

在深入研究了AOP的主题之后,我终于找到了一个可行的解决方案。

最初,我使用以下切入点。

@Aspect
@Component
public static class MyAnnotationAspect {
    /**
     * Matches the execution of any methods in a type annotated with @MyAnnotation.
     */
    @Pointcut("execution(* (@com.test.MyAnnotation *).*(..))")
    public void methodInMyAnnotationType() {}

    /**
     * Matches the execution of any methods annotated with @MyAnnotation.
     */
    @Pointcut("execution(@com.test.MyAnnotation * *.*(..))")
    public void methodAnnotatedWithMyAnnotation() {}

    @Around("methodInMyAnnotationType() || methodAnnotatedWithMyAnnotation()")
    public Object aop(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("AOP IS WORKING");
        return pjp.proceed;
    }
}

我学到的是,只有当我在实际拥有该方法的类上放置@MyAnnotation时,该方法InMyAnanationType切入点才有效。但是,如果我将注释放在扩展类 A 的类 B 上,则 AOP 无法截获类 A 中的方法。

我发现的一个潜在的解决方案如下。

@Pointcut("execution(* *(..)) && @this(com.test.MyAnnotation)")

这意味着切入点是针对当前类和父类的所有方法,并且当前类必须用< code>@MyAnnotation进行注释。看起来很有希望。不幸的是,Spring AOP不支持产生< code > UnsupportedPointcutPrimitiveException 的< code>@this切入点原语。

在深入研究this主题之后,我发现存在targetprimitive,并提出了以下解决方案。

@Pointcut("execution(@com.test.MyAnnotation * *.*(..))")
public void annotatedMethod() {}

@Pointcut("execution(* (@com.test.MyAnnotation *).*(..))")
public void annotatedClass() {}

@Pointcut("execution(* *(..)) && target(com.test.MyAnnotable)")
public void implementedInterface() {}

@Around("annotatedMethod() || annotatedClass() || implementedInterface()")
public Object aop(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("AOP IS WORKING");
    return pjp.proceed;
}

这意味着切入点适用于当前类和父类中的所有方法。此外,该方法必须使用@MyAnnoation进行注释,或者包含该方法的类使用@MyAnnoation进行注释,或者具有该方法的对象必须是标记接口MyAnnote的实例。它看起来不错并且可以工作。

我的最终类实现如下所示。

@Service
public class ShiftModule {
    @Service
    public class Annotated extends ShiftModule implements MyAnnotable {}

    @Resource
    private ShiftModule.Annotated self;
}

附加信息:

在实验过程中,我确实尝试了以下要点。

@Pointcut("@annotation(com.test.MyAnnotation)")
public void annotatedMethod() {}

@Pointcut("@within(com.test.MyAnnotation)")
public void annotatedClass() {}

@Pointcut("target(com.test.MyAnnotable)")
public void implementedInterface() {}

@Around("execution(* *(..)) && (annotatedMethod() || annotatedClass() || implementedInterface()")
public Object aop(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("AOP IS WORKING");
    return pjp.proceed;
}

我发现它不适用于带注释的内部接口,这意味着下面的代码将停止工作。AOP方面根本没有任何影响。

@Repository
public interface OrderRepo extends JpaRepository<Order,Long> {
    @Repository("annotatedOrderRepo")
    @MyAnnotation
    public interface Annotated extends OrderRepo {}
}

丌官绍元
2023-03-14

这不是回答,只是评论太有限,说不出我想说的话。这其实是对OP自己回答的反馈:

>

  • 在Spring AOP中,执行(*(@com.test.MyAnnotation*).*(..))也可以写成@(com.test.CyAnnotation),因为Spring AOP只知道执行连接点。在AspectJ中,您可以添加

    execution(@com.test.MyAnnotation**.*(..))也可以在Spring AOP中写成@annotation(com.test.MyAnnotation),因为Spring AOP只知道执行连接点。在AspectJ中,您可以添加

    我学到的是,只有当我在实际拥有该方法的类上放置@MyAnnotation时,该方法InMyAnanationType切入点才有效。

    当然,因为这是 Java 注释的一般限制。它们永远不会继承到子类,从接口到类或方法,或者从父类方法继承到覆盖子类方法。唯一的例外是,如果您使用@Inherited作为注释类型本身的元注释,那么它将被子类继承(但同样不是从接口到实现类)。此处记录了这一点。

    至于this()vstarget() call() 切入点中的“target”不同,其中“this“是调用方法,“target“是被调用方法。因为call()在SpringAOP中也不可用,所以支持相应的“this”类型切入点是没有意义的。

    如果您愿意切换到AeyJ,我有一个解决方法可以使实现类从接口“继承”注释,并使特定方法也“继承”注释,请参阅此答案。

    我只是出于教育目的提到所有这些,而不是为了取代你自己的解决方案,因为你似乎对标记注释和标记界面的混合很满意。

  •  类似资料:
    • 我试图在切入点中检测用注释注释的类的任何方法。 我试过这个: 但它不起作用。我做错了什么? 谢谢

    • 对于用@X注释的类中的方法或用@X注释的方法,我需要一个切入点。我还需要注释对象。如果类和方法都被注释,我更喜欢将方法注释作为参数。 我尝试了以下操作,这会产生“绑定不一致”的警告。(为什么不直接将其设置为null?) 以下内容创建了“穿过切入点中的“||”的参数x的不明确绑定”警告。(在我看来,这不一定有意义:为什么不绑定第一个短路评估?) 如果存在类和方法注释,则将前面的尝试拆分为两个,自然会

    • 我正在研究一个日志方面,它需要截获所有用自定义注释注释的类和方法。 下面是可以在类和方法上注释的自定义注释类: 我使用这些切入点表达式拦截带有注释的方法和类,这适用于所有简单类,但不适用于扩展或实现的类。 但是对而不是调用通知。 当对任何类或方法应用注释时,如何编写同时拦截对任何子类方法调用的切入点表达式?

    • 问题内容: 我需要 在类中使用@X注释的方法或使用@X注释的方法的切入点 。我还 需要注释对象 。如果同时注释了类和方法,则 我更喜欢将方法注释作为参数 。 我尝试了以下操作,这将创建“不一致的绑定”警告。(为什么不将它们设置为null?) 下面创建“跨’||’的参数x的模糊绑定 在切入点”警告。(我认为这并不一定有意义:为什么不绑定第一个短路评估?) 如果存在类和方法注释,则将先前的尝试自然地分

    • add:如果我将方法存根添加到Fragment2中,就可以开始使用next annotation,但这是一个非常难看的解决方案 解决方案:多亏了@Kriegaex,我找到了解决方案:

    • 我试图在方法注释上创建一个Aeyj切入点,但我总是用不同的方法失败。我使用的是aspectj自动代理(我在Spring上下文中没有配置其他编织)。我的类如下所示: 所以我想知道为什么aspectj不会创建切入点。我设法使用执行(**(…)使其工作抛出一些exc)这对我来说很好,但我仍然想知道我做错了什么。 另外,由于是在接口中定义的,我指定了实现类的注释,有没有办法让它以这种方式工作?其他代理机制