gpt4 book ai didi

java - spring aop可以建议什么样的方法或者spring aop连接点的限制是什么?

转载 作者:行者123 更新时间:2023-12-02 08:41:14 24 4
gpt4 key购买 nike

我正在使用spring aop,我发现有3种情况,但我不太清楚:情况1:单个类不实现或扩展任何类或接口(interface)在这种情况下,任何非私有(private)方法都将成为连接点

情况2:类实现接口(interface)并实现方法在这种情况下,只有接口(interface)中声明的方法才是连接点

情况3:一个类扩展了一个父类(super class)并覆盖了父类(super class)的方法在这种情况下,所有子类的方法都不会是连接点。

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.functionSubJdkProxy() 无法被建议。

抱歉,由于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 代理模式。您必须设置一个经典的 Spring 项目,并且类路径上没有任何 Boot 依赖项。但是,当然只有接口(interface)定义的方法被代理,并且您不能使用接口(interface)外部定义的方法。您也可以将 Spring 切换到 CGLIB 模式,但不能将 Boot 切换到 JDK 模式。

因为这是一个常见问题,而且我喜欢有一个 Playground 项目来回答相关问题,所以我发布了 this GitHub project为了您的方便。请随意检查它、克隆它并使用它。

<小时/>

2022年2月26日更新: Here您可以学习如何使用 Spring 自己的 AopUtils 辅助类来确定 Spring AOP 代理类型(JDK 与 CGLIB 代理)。

关于java - spring aop可以建议什么样的方法或者spring aop连接点的限制是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61382719/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com