除此以外,aspectj 提供了两种另外的 AOP 底层实现:
简单比较的话:
代码参考项目 demo6_advanced_aspectj_01
注意
代码参考项目 demo6_advanced_aspectj_02
public class JdkProxyDemo {
interface Foo {
void foo();
}
static class Target implements Foo {
public void foo() {
System.out.println("target foo");
}
}
public static void main(String[] param) {
// 目标对象
Target target = new Target();
// 代理对象
Foo proxy = (Foo) Proxy.newProxyInstance(
Target.class.getClassLoader(), new Class[]{Foo.class},
(p, method, args) -> {
System.out.println("proxy before...");
Object result = method.invoke(target, args);
System.out.println("proxy after...");
return result;
});
// 调用代理
proxy.foo();
}
}
运行结果
proxy before...
target foo
proxy after...
public class CglibProxyDemo {
static class Target {
public void foo() {
System.out.println("target foo");
}
}
public static void main(String[] param) {
// 目标对象
Target target = new Target();
// 代理对象
Target proxy = (Target) Enhancer.create(Target.class,
(MethodInterceptor) (p, method, args, methodProxy) -> {
System.out.println("proxy before...");
Object result = methodProxy.invoke(target, args);
// 另一种调用方法,不需要目标对象实例
// Object result = methodProxy.invokeSuper(p, args);
System.out.println("proxy after...");
return result;
});
// 调用代理
proxy.foo();
}
}
运行结果与 jdk 动态代理相同
public class A12 {
interface Foo {
void foo();
int bar();
}
static class Target implements Foo {
public void foo() {
System.out.println("target foo");
}
public int bar() {
System.out.println("target bar");
return 100;
}
}
public static void main(String[] param) {
// ⬇️1. 创建代理,这时传入 InvocationHandler
Foo proxy = new $Proxy0(new InvocationHandler() {
// ⬇️5. 进入 InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
// ⬇️6. 功能增强
System.out.println("before...");
// ⬇️7. 反射调用目标方法
return method.invoke(new Target(), args);
}
});
// ⬇️2. 调用代理方法
proxy.foo();
proxy.bar();
}
}
模拟代理实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
// ⬇️这就是 jdk 代理类的源码, 秘密都在里面
public class $Proxy0 extends Proxy implements A12.Foo {
public $Proxy0(InvocationHandler h) {
super(h);
}
// ⬇️3. 进入代理方法
public void foo() {
try {
// ⬇️4. 回调 InvocationHandler
h.invoke(this, foo, new Object[0]);
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public int bar() {
try {
Object result = h.invoke(this, bar, new Object[0]);
return (int) result;
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
static Method foo;
static Method bar;
static {
try {
foo = A12.Foo.class.getMethod("foo");
bar = A12.Foo.class.getMethod("bar");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
}
代理一点都不难,无非就是利用了多态、反射的知识
com.libin.a12.TestMethodInvoke
注意 运行时请添加 --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED
com.libin.a13 包
和 jdk 动态代理原理查不多
public class A14Application {
public static void main(String[] args) throws InvocationTargetException {
Target target = new Target();
Proxy proxy = new Proxy();
proxy.setCallbacks(new Callback[]{(MethodInterceptor) (p, m, a, mp) -> {
System.out.println("proxy before..." + mp.getSignature());
// ⬇️调用目标方法(三种)
// Object result = m.invoke(target, a); // ⬅️反射调用
// Object result = mp.invoke(target, a); // ⬅️非反射调用, 结合目标用
Object result = mp.invokeSuper(p, a); // ⬅️非反射调用, 结合代理用
System.out.println("proxy after..." + mp.getSignature());
return result;
}});
// ⬇️调用代理方法
proxy.save();
}
}
注意
com.libin.a13.ProxyFastClass,com.libin.a13.TargetFastClass
Spring 中对切点、通知、切面的抽象如下
#mermaid-svg-pVowWwihHPBpuHRQ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-pVowWwihHPBpuHRQ .error-icon{fill:#552222;}#mermaid-svg-pVowWwihHPBpuHRQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pVowWwihHPBpuHRQ .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-pVowWwihHPBpuHRQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pVowWwihHPBpuHRQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pVowWwihHPBpuHRQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pVowWwihHPBpuHRQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pVowWwihHPBpuHRQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pVowWwihHPBpuHRQ .marker.cross{stroke:#333333;}#mermaid-svg-pVowWwihHPBpuHRQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pVowWwihHPBpuHRQ g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-pVowWwihHPBpuHRQ g.classGroup text .title{font-weight:bolder;}#mermaid-svg-pVowWwihHPBpuHRQ .nodeLabel,#mermaid-svg-pVowWwihHPBpuHRQ .edgeLabel{color:#131300;}#mermaid-svg-pVowWwihHPBpuHRQ .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-pVowWwihHPBpuHRQ .label text{fill:#131300;}#mermaid-svg-pVowWwihHPBpuHRQ .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-pVowWwihHPBpuHRQ .classTitle{font-weight:bolder;}#mermaid-svg-pVowWwihHPBpuHRQ .node rect,#mermaid-svg-pVowWwihHPBpuHRQ .node circle,#mermaid-svg-pVowWwihHPBpuHRQ .node ellipse,#mermaid-svg-pVowWwihHPBpuHRQ .node polygon,#mermaid-svg-pVowWwihHPBpuHRQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pVowWwihHPBpuHRQ .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-pVowWwihHPBpuHRQ g.clickable{cursor:pointer;}#mermaid-svg-pVowWwihHPBpuHRQ g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-pVowWwihHPBpuHRQ g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-pVowWwihHPBpuHRQ .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-pVowWwihHPBpuHRQ .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-pVowWwihHPBpuHRQ .dashed-line{stroke-dasharray:3;}#mermaid-svg-pVowWwihHPBpuHRQ #compositionStart,#mermaid-svg-pVowWwihHPBpuHRQ .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ #compositionEnd,#mermaid-svg-pVowWwihHPBpuHRQ .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ #dependencyStart,#mermaid-svg-pVowWwihHPBpuHRQ .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ #dependencyStart,#mermaid-svg-pVowWwihHPBpuHRQ .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ #extensionStart,#mermaid-svg-pVowWwihHPBpuHRQ .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ #extensionEnd,#mermaid-svg-pVowWwihHPBpuHRQ .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ #aggregationStart,#mermaid-svg-pVowWwihHPBpuHRQ .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ #aggregationEnd,#mermaid-svg-pVowWwihHPBpuHRQ .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-pVowWwihHPBpuHRQ .edgeTerminals{font-size:11px;}#mermaid-svg-pVowWwihHPBpuHRQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
一
一
«interface»
Advice
«interface»
MethodInterceptor
«interface»
Advisor
«interface»
PointcutAdvisor
«interface»
Pointcut
AspectJExpressionPointcut
代理相关类图
#mermaid-svg-zcqZa4TA0vMykmOm {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-zcqZa4TA0vMykmOm .error-icon{fill:#552222;}#mermaid-svg-zcqZa4TA0vMykmOm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zcqZa4TA0vMykmOm .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-zcqZa4TA0vMykmOm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zcqZa4TA0vMykmOm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zcqZa4TA0vMykmOm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zcqZa4TA0vMykmOm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zcqZa4TA0vMykmOm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zcqZa4TA0vMykmOm .marker.cross{stroke:#333333;}#mermaid-svg-zcqZa4TA0vMykmOm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zcqZa4TA0vMykmOm g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-zcqZa4TA0vMykmOm g.classGroup text .title{font-weight:bolder;}#mermaid-svg-zcqZa4TA0vMykmOm .nodeLabel,#mermaid-svg-zcqZa4TA0vMykmOm .edgeLabel{color:#131300;}#mermaid-svg-zcqZa4TA0vMykmOm .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-zcqZa4TA0vMykmOm .label text{fill:#131300;}#mermaid-svg-zcqZa4TA0vMykmOm .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-zcqZa4TA0vMykmOm .classTitle{font-weight:bolder;}#mermaid-svg-zcqZa4TA0vMykmOm .node rect,#mermaid-svg-zcqZa4TA0vMykmOm .node circle,#mermaid-svg-zcqZa4TA0vMykmOm .node ellipse,#mermaid-svg-zcqZa4TA0vMykmOm .node polygon,#mermaid-svg-zcqZa4TA0vMykmOm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zcqZa4TA0vMykmOm .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-zcqZa4TA0vMykmOm g.clickable{cursor:pointer;}#mermaid-svg-zcqZa4TA0vMykmOm g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-zcqZa4TA0vMykmOm g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-zcqZa4TA0vMykmOm .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-zcqZa4TA0vMykmOm .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-zcqZa4TA0vMykmOm .dashed-line{stroke-dasharray:3;}#mermaid-svg-zcqZa4TA0vMykmOm #compositionStart,#mermaid-svg-zcqZa4TA0vMykmOm .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm #compositionEnd,#mermaid-svg-zcqZa4TA0vMykmOm .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm #dependencyStart,#mermaid-svg-zcqZa4TA0vMykmOm .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm #dependencyStart,#mermaid-svg-zcqZa4TA0vMykmOm .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm #extensionStart,#mermaid-svg-zcqZa4TA0vMykmOm .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm #extensionEnd,#mermaid-svg-zcqZa4TA0vMykmOm .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm #aggregationStart,#mermaid-svg-zcqZa4TA0vMykmOm .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm #aggregationEnd,#mermaid-svg-zcqZa4TA0vMykmOm .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-zcqZa4TA0vMykmOm .edgeTerminals{font-size:11px;}#mermaid-svg-zcqZa4TA0vMykmOm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
多
使用
创建
创建
«interface»
Advised
ProxyFactory
proxyTargetClass : boolean
Target
Advisor
«interface»
AopProxyFactory
«interface»
AopProxy
+getProxy() : Object
基于CGLIB的Proxy
ObjenesisCglibAopProxy
advised : ProxyFactory
JdkDynamicAopProxy
advised : ProxyFactory
基于JDK的Proxy
com.libin.a15.A15
注意
com.libin.a16.A16
org.springframework.aop.framework.autoproxy 包
org.springframework.aop.framework.autoproxy.A17_1
org.springframework.aop.framework.autoproxy.A17_2
代理对象调用流程如下(以 JDK 动态代理实现为例)
图中不同颜色对应一次环绕通知或目标的调用起始至终结
#mermaid-svg-QGelvNtNjA07IKdL {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QGelvNtNjA07IKdL .error-icon{fill:#552222;}#mermaid-svg-QGelvNtNjA07IKdL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QGelvNtNjA07IKdL .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-QGelvNtNjA07IKdL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QGelvNtNjA07IKdL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QGelvNtNjA07IKdL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QGelvNtNjA07IKdL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QGelvNtNjA07IKdL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QGelvNtNjA07IKdL .marker.cross{stroke:#333333;}#mermaid-svg-QGelvNtNjA07IKdL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QGelvNtNjA07IKdL .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QGelvNtNjA07IKdL text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-QGelvNtNjA07IKdL .actor-line{stroke:grey;}#mermaid-svg-QGelvNtNjA07IKdL .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-QGelvNtNjA07IKdL .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-QGelvNtNjA07IKdL #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-QGelvNtNjA07IKdL .sequenceNumber{fill:white;}#mermaid-svg-QGelvNtNjA07IKdL #sequencenumber{fill:#333;}#mermaid-svg-QGelvNtNjA07IKdL #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-QGelvNtNjA07IKdL .messageText{fill:#333;stroke:#333;}#mermaid-svg-QGelvNtNjA07IKdL .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QGelvNtNjA07IKdL .labelText,#mermaid-svg-QGelvNtNjA07IKdL .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-QGelvNtNjA07IKdL .loopText,#mermaid-svg-QGelvNtNjA07IKdL .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-QGelvNtNjA07IKdL .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QGelvNtNjA07IKdL .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-QGelvNtNjA07IKdL .noteText,#mermaid-svg-QGelvNtNjA07IKdL .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-QGelvNtNjA07IKdL .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QGelvNtNjA07IKdL .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QGelvNtNjA07IKdL .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QGelvNtNjA07IKdL .actorPopupMenu{position:absolute;}#mermaid-svg-QGelvNtNjA07IKdL .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-QGelvNtNjA07IKdL .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QGelvNtNjA07IKdL .actor-man circle,#mermaid-svg-QGelvNtNjA07IKdL line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-QGelvNtNjA07IKdL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Proxy InvocationHandler MethodInvocation ProxyFactory MethodInterceptor1 MethodInterceptor2 Target invoke() 获得 Target 获得 MethodInterceptor 链 创建 mi mi.proceed() invoke(mi) 前增强 mi.proceed() invoke(mi) 前增强 mi.proceed() mi.invokeJoinPoint() 结果 后增强 结果 后增强 结果 Proxy InvocationHandler MethodInvocation ProxyFactory MethodInterceptor1 MethodInterceptor2 Target
org.springframework.aop.framework.A18
代理方法执行时会做如下工作
org.springframework.aop.framework.A18_1
MethodInvocation 的编程技巧在实现拦截器、过滤器时能用上
org.springframework.aop.framework.autoproxy.A19
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、评论、收藏➕关注,您的支持是我坚持写作最大的动力。