Spring AOP可以建议使用哪种方法,或者Spring AOP连接点的限制是什么? [英] what kind of method can be advised by spring aop or what's a spring aop joinpoint's limitation?

查看:0
本文介绍了Spring AOP可以建议使用哪种方法,或者Spring AOP连接点的限制是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Spring AOP,我发现有3种情况,但我不太清楚: 情形1:没有实现或扩展任何类或接口的单个类 在这种情况下,任何非私有方法都将是连接点

情形2:类实现接口并实现方法 在此缝合中,只有在接口中声明的方法将是连接点

情形3:类扩展超类并覆盖超类的方法 在此缝合中,所有子类的方法都不是连接点。

Spring AOP就是这样设计的吗?

以下是我使用的代码:

JdkProxyInterface.java

package com.example.proxytestdemo;

public interface JdkProxyInterface {

    void function(int i);
}

JdkProxy.java

package com.example.proxytestdemo;
import org.springframework.stereotype.Component;

@Component
public class JdkProxy implements JdkProxyInterface {

    @Override
    @TimeIt
    public void function(int i) {
        System.out.println("JdkProxy function");
    }

    @TimeIt
    public void function1(int i) {
        System.out.println("JdkProxy function");
    }

    @TimeIt
    public void function2(int i) {
        System.out.println("JdkProxy function");
    }

}

SubJdkProxy.java

package com.example.proxytestdemo;

import org.springframework.stereotype.Component;

@Component
public class SubJdkProxy extends JdkProxy {

    @TimeIt
    public void functionSubJdkProxy(int i) {
        System.out.println("functionSubJdkProxy");
    }
}

TimeIt.Java

package com.example.proxytestdemo;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Inherited
public @interface TimeIt {
    boolean enabled() default true;
}

TimePointCut.java

package com.example.proxytestdemo;

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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;


@Aspect
@Component
public class TimePointCut {

    @Pointcut("execution(* com.example.proxytestdemo..*(..))")
    public void calcTime1() {
    }

    @Around(value = "calcTime1()")
    public Object aspectProcess(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("proxy begin....... ");
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        TimeIt annotation = method.getAnnotation(com.example.proxytestdemo.TimeIt.class);
        if (annotation == null) {
            annotation = pjp.getTarget().getClass().getAnnotation(TimeIt.class);
            if (annotation == null) {
                for (Class<?> cls : pjp.getClass().getInterfaces()) {
                    annotation = cls.getAnnotation(TimeIt.class);
                    if (annotation != null) {
                        break;
                    }
                }
            }
        }
        if (annotation != null) {
            System.out.println(annotation.enabled());
        }
        Object o = null;
        long t1 = 0, t2 = 0;
        try {
            t1 = System.currentTimeMillis();
            o = pjp.proceed();
            t2 = System.currentTimeMillis();
        } catch (Exception e) {
            throw e;
        } finally {
            System.out.println("proxy end....... ");
            System.out.println("time cost: "+ (t2-t1)/1000 + "s");
        }

        return o;
    }
}

我发现不能建议使用JdkProxy.unction1()和JdkProxy.unction2()和SubJdkProxy.unctionSubJdkProxy()。

对不起,由于IDEA的提示,我犯了一个错误。IDEA's hint

推荐答案

您的应用程序应该可以工作。听着,我尝试了各种组合,它们都很管用:

驱动程序应用程序:

package com.example.proxytestdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {
  public static void main(String[] args) {
    try (ConfigurableApplicationContext context = SpringApplication.run(Application.class, args)) {
      doStuff(context);
    }
  }

  private static void doStuff(ConfigurableApplicationContext context) {
    JdkProxy jdkProxy = (JdkProxy) context.getBean("jdkProxy");
    jdkProxy.function(11);
    jdkProxy.function1(22);
    jdkProxy.function2(33);
    System.out.println("----------");

    JdkProxyInterface jdkProxyInterface = jdkProxy ;
    jdkProxyInterface.function(11);
    System.out.println("==========");

    SubJdkProxy subJdkProxy = (SubJdkProxy) context.getBean("subJdkProxy");
    subJdkProxy.function(11);
    subJdkProxy.function1(22);
    subJdkProxy.function2(33);
    subJdkProxy.functionSubJdkProxy(44);
    System.out.println("----------");

    jdkProxyInterface = subJdkProxy;
    jdkProxyInterface.function(11);
  }
}

控制台日志:

execution(void com.example.proxytestdemo.JdkProxy.function(int))
JdkProxy function
execution(void com.example.proxytestdemo.JdkProxy.function1(int))
JdkProxy function
execution(void com.example.proxytestdemo.JdkProxy.function2(int))
JdkProxy function
----------
execution(void com.example.proxytestdemo.JdkProxy.function(int))
JdkProxy function
==========
execution(void com.example.proxytestdemo.JdkProxy.function(int))
JdkProxy function
execution(void com.example.proxytestdemo.JdkProxy.function1(int))
JdkProxy function
execution(void com.example.proxytestdemo.JdkProxy.function2(int))
JdkProxy function
execution(void com.example.proxytestdemo.SubJdkProxy.functionSubJdkProxy(int))
functionSubJdkProxy
----------
execution(void com.example.proxytestdemo.JdkProxy.function(int))
JdkProxy function

顺便说一句,为了专注于基础工作,我将方面的建议方法简化为:

      @Around(value = "calcTime1()")
      public Object aspectProcess(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println(pjp);
        return pjp.proceed();
      }

更新:

Spring Boot默认为CGLIB代理模式,当前无法轻松重新配置为使用JDK代理,因为相应的注释被忽略或被取代,请参见issue #12194。但我找到了一种方法,见my comment on Spring Boot #27375。您需要将此内容放入application.properties

spring.aop.proxy-target-class=false

但是,普通Spring默认使用JDK代理模式。您必须在类路径上设置一个没有任何Boot依赖项的经典Spring项目。但是,当然,只有接口定义的方法被代理,您不能使用在接口外部定义的方法。您也可以将Spring切换到CGLIB模式,但不能将其引导到JDK模式。

因为这是一个常见的问题,而且我喜欢有一个游乐场项目来回答相关的问题,为了您的方便,我发布了this GitHub project。您可以随意查看它、克隆它并玩弄它。


更新2022-02-26:Here您可以学习如何使用Spring自己的帮助器类确定Spring AOP代理类型(JDK与CGLIB代理)。

这篇关于Spring AOP可以建议使用哪种方法,或者Spring AOP连接点的限制是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆