Какой метод можно посоветовать в Spring AOP или в чем заключается ограничение точки соединения Spring AOP? - PullRequest
0 голосов
/ 23 апреля 2020

Я работаю с 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.function1 () и JdkProxy.function2 () и SubJdkProxy.functionSubJd kProxy () не может быть рекомендовано.

Извините, я сделал ошибку из-за подсказки IDEA. подсказка IDEA

1 Ответ

1 голос
/ 23 апреля 2020

Ваше приложение должно работать. Смотри, я перепробовал все виды комбинаций, все они работают:

Приложение драйвера:

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 .

Однако обычный ванильный Spring по умолчанию JDK прокси режим . Вы должны настроить классический проект Spring без каких-либо загрузочных зависимостей на вашем пути к классам. Но тогда, конечно, только прокси-методы, определенные интерфейсом, и вы не можете использовать методы, определенные вне интерфейсов. Вы также можете переключить Spring в режим CGLIB, но не Boot to JDK.

Поскольку это общий вопрос, и мне все равно хотелось бы иметь проект игровой площадки для ответов на связанные вопросы, я опубликовал этот проект GitHub для вашего удобства. Не стесняйтесь осмотреть его, клонировать и поиграть с ним.

...