本文介紹了Spring AOP可以建議使用哪種方法,或者Spring AOP連接點的限制是什么?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我正在使用Spring AOP,我發(fā)現(xiàn)有3種情況,但我不太清楚:
情形1:沒有實現(xiàn)或擴展任何類或接口的單個類
在這種情況下,任何非私有方法都將是連接點
情形2:類實現(xiàn)接口并實現(xiàn)方法
在此縫合中,只有在接口中聲明的方法將是連接點
情形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;
}
}
我發(fā)現(xiàn)不能建議使用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依賴項的經(jīng)典Spring項目。但是,當然,只有接口定義的方法被代理,您不能使用在接口外部定義的方法。您也可以將Spring切換到CGLIB模式,但不能將其引導到JDK模式。
因為這是一個常見的問題,而且我喜歡有一個游樂場項目來回答相關的問題,為了您的方便,我發(fā)布了this GitHub project。您可以隨意查看它、克隆它并玩弄它。
更新2022-02-26:Here您可以學習如何使用Spring自己的幫助器類確定Spring AOP代理類型(JDK與CGLIB代理)。
這篇關于Spring AOP可以建議使用哪種方法,或者Spring AOP連接點的限制是什么?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,