9) AOP 实现之 ajc 编译器
代码参考项目 demo6_advanced_aspectj_01
收获💡
编译器也能修改 class 实现增强
编译器增强能突破代理仅能通过方法重写增强的限制:可以对构造方法、静态方法等实现增强
项目地址:demo6_advanced_aspectj_01https://github.com/LJay997/demo6_advanced_aspectj_01
查看IDEA 编译的class文件可看出ajc帮我们修改了源码实现了增强静态方法
10) AOP 实现之 agent 类加载
代码参考项目 demo6_advanced_aspectj_02
收获💡
类加载时可以通过 agent 修改 class 实现增强
demo6_advanced_aspectj_02https://github.com/LJay997/demo6_advanced_aspectj_02项目地址:git@github.com:LJay997/demo6_advanced_aspectj_02.git
使用 Alibaba开源的Java诊断工具 Arthas
https://github.com/alibaba/arthas/blob/master/README_CN.md 反编译运行时的文件

下载arthas-boot.jar
,然后用java -jar
的方式启动:
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
运行 A10,选择3
运行成功后 使用命令 jad (Decompile class 使用 help命令可查看帮助)
jad jad com.itheima.service.MyService
查看运行时编译文件。可见 aop foo()foo()内部又调用了自己的 bar()也可以被增强的。
Spring Aop失效的情況及解决办法http://t.csdn.cn/aRC6D
11) AOP 实现之 proxy
演示1 - jdk 动态代理
interface Foo {
void foo();
int bar();
}
class Target implements Foo {
@Override
public int bar() {
return 0;
}
@Override
public void foo() {
System.out.println("target foo");
}
}
public class JdkProxy {
public static void main(String[] args) throws IOException {
// method.invoke 需要传递 target
Target target = new Target();
ClassLoader loader = JdkProxy.class.getClassLoader();
// Proxy.newProxyInstance ClassLoader [] Class<?>[]
// java.lang.reflect 生成的代理对象需要是接口实现的方法 代理与目标是同级关系
Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (tmpProxy, method, args1) -> {
System.out.println("before");
// method.invoke 参数1 需要传递
return method.invoke(target, args1);
});
// 执行代理方法
proxy.foo();
// 获取当前代理方法的类
System.out.println(proxy.getClass());
// 防止程序自己终止
System.in.read();
}
}
使用arthas工具查看 JdkProxy运行期间动态生成(ASM)生成的代理类的源码。
# 运行 arthas
java -jar .\arthas-boot.jar
# 查看到程序的代号输入(回车确认)
4
# jad 命令反编译
jad $Proxy0
arthas 获取的源码JdkProxy
package a11;
import a11.Foo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
final class $Proxy0
extends Proxy
implements Foo {
// 获取接口所有的方法
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
// 实现构造方法 Proxy
public $Proxy0(InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final boolean equals(Object object) {
try {
return (Boolean)this.h.invoke(this, m1, new Object[]{object});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int bar() {
try {
return (Integer)this.h.invoke(this, m3, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void foo() {
try {
this.h.invoke(this, m4, null);
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return (Integer)this.h.invoke(this, m0, null);
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("a11.Foo").getMethod("bar", new Class[0]);
m4 = Class.forName("a11.Foo").getMethod("foo", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
}
catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
使用IDEA插件ASM加载字节码文件
main 方法中补充
byte[] dump = $Proxy0Dump.dump();
ClassLoader classLoader = new ClassLoader() {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 将字节数组转换为Class 类的实例
return super.defineClass(name, dump, 0, dump.length);
}
};
Class<?> proxy0 = classLoader.loadClass("$Proxy0");
Constructor<?> constructor = proxy0.getConstructor(InvocationHandler.class);
Foo proxy = (Foo)constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return null;
}
});
proxy.foo();
// .....JDK 代理方法
Target target = new Target();
// ......
JDK 代理的优化
在反射调用第17次时候 代理类变化了
16:jdk.internal.reflect.NativeMethodAccessorImpl@cb5822 ->
17:jdk.internal.reflect.GeneratedMethodAccessor2@26653222
public class TestMethodInvoke {
public static void main(String[] args) throws Exception {
Method foo = TestMethodInvoke.class.getMethod("foo", int.class);
for (int i = 1; i <= 17; i++) {
show(i, foo);
foo.invoke(null, i);
}
System.in.read();
}
// 方法反射调用时, 底层 MethodAccessor 的实现类
private static void show(int i, Method foo) throws Exception {
Method getMethodAccessor = Method.class.getDeclaredMethod("getMethodAccessor");
getMethodAccessor.setAccessible(true);
Object invoke = getMethodAccessor.invoke(foo);
if (invoke == null) {
System.out.println(i + ":" + null);
return;
}
Field delegate = Class.forName("jdk.internal.reflect.DelegatingMethodAccessorImpl").getDeclaredField("delegate");
delegate.setAccessible(true);
System.out.println(i + ":" + delegate.get(invoke));
}
public static void foo(int i) {
System.out.println(i + ":" + "foo");
}
}
收获💡
jdk 动态代理要求目标必须实现接口,生成的代理类实现相同接口,因此代理与目标之间是平级兄弟关系
演示2 - cglib 代理
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.io.IOException;
import java.lang.reflect.Method;
public class CglibProxy {
static class Target {
void foo() {
System.out.println("target foo");
}
}
public static void main(String[] args) throws IOException {
Target target = new Target();
// public static Object create(Class type, Callback callback) 第二个参数 使用 MethodInterceptor extends Callback
// cglib 生产的类型为目标类型的 子类型(方法重写) 目标方法&目标类不能是final类型的
Target proxy = (Target)Enhancer.create(Target.class, new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before");
// Object invoke = method.invoke(target, objects); // 用方法反射调用目标
Object invoke = methodProxy.invoke(target, objects); // 没有用反射 - 推荐
// Object invoke = methodProxy.invokeSuper(o, objects); // 没有用反射 需要代理
System.out.println("after");
return invoke;
}
});
proxy.foo();
System.out.println(proxy.getClass());
System.in.read();
}
}
arthas 获取运行时class
package a11;
import a11.CglibProxy;
import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class CglibProxy$Target$$EnhancerByCGLIB$$f6222c24
extends CglibProxy.Target
implements Factory {
// Method MethodProxy 重点
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$foo$0$Method;
private static final MethodProxy CGLIB$foo$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class<?> clazz = Class.forName("a11.CglibProxy$Target$$EnhancerByCGLIB$$f6222c24");
Class<?> clazz2 = Class.forName("java.lang.Object");
Method[] methodArray = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, clazz2.getDeclaredMethods());
CGLIB$equals$1$Method = methodArray[0];
CGLIB$equals$1$Proxy = MethodProxy.create(clazz2, clazz, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = methodArray[1];
CGLIB$toString$2$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = methodArray[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(clazz2, clazz, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = methodArray[3];
CGLIB$clone$4$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
clazz2 = Class.forName("a11.CglibProxy$Target");
CGLIB$foo$0$Method = ReflectUtils.findMethods(new String[]{"foo", "()V"}, clazz2.getDeclaredMethods())[0];
CGLIB$foo$0$Proxy = MethodProxy.create(clazz2, clazz, "()V", "foo", "CGLIB$foo$0");
}
// 带原始功能的方法
final void CGLIB$foo$0() {
super.foo();
}
// 带增强功能的方法
@Override
final void foo() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object = methodInterceptor.intercept(this, CGLIB$foo$0$Method, CGLIB$emptyArgs, CGLIB$foo$0$Proxy);
return;
}
super.foo();
}
final boolean CGLIB$equals$1(Object object) {
return super.equals(object);
}
public final boolean equals(Object object) {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object2 = methodInterceptor.intercept(this, CGLIB$equals$1$Method, new Object[]{object}, CGLIB$equals$1$Proxy);
return object2 == null ? false : (Boolean)object2;
}
return super.equals(object);
}
final String CGLIB$toString$2() {
return super.toString();
}
public final String toString() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
return (String)methodInterceptor.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy);
}
return super.toString();
}
final int CGLIB$hashCode$3() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
Object object = methodInterceptor.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return object == null ? 0 : ((Number)object).intValue();
}
return super.hashCode();
}
final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
return methodInterceptor.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy);
}
return super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature signature) {
String string = ((Object)signature).toString();
switch (string.hashCode()) {
case -1268936465: {
if (!string.equals("foo()V")) break;
return CGLIB$foo$0$Proxy;
}
case -508378822: {
if (!string.equals("clone()Ljava/lang/Object;")) break;
return CGLIB$clone$4$Proxy;
}
case 1826985398: {
if (!string.equals("equals(Ljava/lang/Object;)Z")) break;
return CGLIB$equals$1$Proxy;
}
case 1913648695: {
if (!string.equals("toString()Ljava/lang/String;")) break;
return CGLIB$toString$2$Proxy;
}
case 1984935277: {
if (!string.equals("hashCode()I")) break;
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
public CglibProxy$Target$$EnhancerByCGLIB$$f6222c24() {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(cglibProxy$Target$$EnhancerByCGLIB$$f6222c24);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] callbackArray) {
CGLIB$THREAD_CALLBACKS.set(callbackArray);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callbackArray) {
CGLIB$STATIC_CALLBACKS = callbackArray;
}
private static final void CGLIB$BIND_CALLBACKS(Object object) {
block2: {
Object object2;
block3: {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = (CglibProxy$Target$$EnhancerByCGLIB$$f6222c24)object;
if (cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BOUND) break block2;
cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BOUND = true;
object2 = CGLIB$THREAD_CALLBACKS.get();
if (object2 != null) break block3;
object2 = CGLIB$STATIC_CALLBACKS;
if (CGLIB$STATIC_CALLBACKS == null) break block2;
}
cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])object2)[0];
}
}
@Override
public Object newInstance(Callback[] callbackArray) {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
}
@Override
public Object newInstance(Callback callback) {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(new Callback[]{callback});
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
}
@Override
public Object newInstance(Class[] classArray, Object[] objectArray, Callback[] callbackArray) {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
Class[] classArray2 = classArray;
switch (classArray.length) {
case 0: {
cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
break;
}
default: {
throw new IllegalArgumentException("Constructor not found");
}
}
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
}
@Override
public Callback getCallback(int n) {
MethodInterceptor methodInterceptor;
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
switch (n) {
case 0: {
methodInterceptor = this.CGLIB$CALLBACK_0;
break;
}
default: {
methodInterceptor = null;
}
}
return methodInterceptor;
}
@Override
public void setCallback(int n, Callback callback) {
switch (n) {
case 0: {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
break;
}
}
}
@Override
public Callback[] getCallbacks() {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
return new Callback[]{this.CGLIB$CALLBACK_0};
}
@Override
public void setCallbacks(Callback[] callbackArray) {
Callback[] callbackArray2 = callbackArray;
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
this.CGLIB$CALLBACK_0 = (MethodInterceptor)callbackArray[0];
}
static {
CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$STATICHOOK1();
}
}
15) jdk 和 cglib 在 Spring 中的统一
AOP名词解释Advice,Pointcut,Advisor,Joinpoint,Advised是什么?
Spring 中对切点、通知、切面的抽象如下
切点:接口 Pointcut,典型实现 AspectJExpressionPointcut(在哪些地方增强)
通知:Advice 该接口仅仅作为标记使用 没做实质性的方法 典型使用的接口为 MethodInterceptor 所有通知会被统一转换为环绕通知 适配器模式的体现
MethodInterceptor 中可以间接的获取到 Joinpoint 的方法
切面:Advisor,包含一个 Advice 通知,PointcutAdvisor 包含一个 Advice 通知和一个 Pointcut(哪个人 在哪个地方Pointcut 做什么事情Advice)
代理相关类图(代理工厂需要 目标类(Target) + 哪个人(Advisor)即可完成 代理者的创建(Proxy) )
AopProxyFactory 根据 proxyTargetClass 等设置选择 AopProxy 实现
AopProxy 通过 getProxy 创建代理对象
图中 Proxy 都实现了 Advised 接口,能够获得关联的切面集合与目标(其实是从 ProxyFactory 取得)
调用代理方法时,会借助 ProxyFactory 将通知统一转为环绕通知:MethodInterceptor
// 1.未setInterfaces 未 setTargetClass CGLIB
// 2.setInterfaces 未 setTargetClass JDKProxy
// 3. setTargetClass CGLIB
AOP名词解释Advice,Pointcut,Advisor,Joinpoint,Advised是什么?
http://t.csdn.cn/tPUqD
interface I1 {
void foo();
void bar();
}
static class Target1 implements I1 {
public void foo() {
System.out.println("target1 foo");
}
public void bar() {
System.out.println("target1 bar");
}
}
static class Target2 {
public void foo() {
System.out.println("target2 foo");
}
public void bar() {
System.out.println("target2 bar");
}
}
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class Demo {
public static void main(String[] args) {
// 1.添加切入点 pointcut
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* foo())");
// 2.添加通知Advice org.aopalliance.intercept.MethodInterceptor
MethodInterceptor advice = invocation -> {
System.out.println("before");
Object proceed = invocation.proceed(); // 调用目标
System.out.println("after");
return proceed;
};
// 3.添加切面 Advisor !! 重要 反向查找就是找一下 advisor 下有 pointcut实现类 的类就可以了!!
// DefaultPointcutAdvisor 与 AspectJExpressionPointcut 同属于 AbstractGenericPointcutAdvisor
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
// 4. 创建代理
A15.Target1 target = new A15.Target1();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(target.getClass().getInterfaces()); // 如果实现了接口必须setInterfaces ProxyFactory不会自动检测
// proxyFactory.setTargetClass(target.getClass()); // proxyFactory.getProxy使用的 CGLIB 实现 返回类型需要改为 I1 的子类
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
A15.I1 proxy = (A15.I1)proxyFactory.getProxy();
proxy.foo();
System.out.println(proxy.getClass());
// spring 代理的实现由两种 JDKProxy 与 CGLIB
// 1.未setInterfaces 未 setTargetClass CGLIB
// 2.setInterfaces 未 setTargetClass JDKProxy
// 3. setTargetClass CGLIB
}
}
proxyFactory.setInterfaces(target.getClass().getInterfaces()); proxyFactory.setTargetClass(target.getClass());
切点匹配
PointCut 的重要属性 org.springframework.aop.MethodMatcher 检查目标方法是否有资格获得advice
对使用了注解标注(对整个类型层次结构执行完整搜索,包括超类和实现的接口)的方法进行增强
StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut() {
// 执行静态检查给定方法是否匹配
@Override
public boolean matches(Method method, Class<?> targetClass) {
// MergedAnnotations可以从任何 Java AnnotatedElement获得。
// 可以使用不同的搜索策略来定位包含要聚合的注释的相关源元素。
// 例如, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY将搜索超类和实现的接口。
// 检查方法上是否加了 Transactional 注解
MergedAnnotations annotations = MergedAnnotations.from(method);
if (annotations.isPresent(Transactional.class)) {
return true;
}
//
// 查看类上是否加了 Transactional 注解
annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
if (annotations.isPresent(Transactional.class)) {
return true;
}
return false;
}
};
System.out.println(pt3.matches(T1.class.getMethod("foo"), T1.class));
17) 从 @Aspect 到 Advisor
代理创建器
代码参考
org.springframework.aop.framework.autoproxy 包
package org.springframework.aop.framework.autoproxy;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.lang.NonNull;
import java.util.List;
public class A17 {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("aspect1", Aspect1.class);
context.registerBean("config", Config.class);
context.registerBean(ConfigurationClassPostProcessor.class);
// 属于 BeanPostProcessor 初始化回调前(通过标记接口等填充 bean) 初始化回调后(而使用代理包装 bean)
context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
// BeanPostProcessor
// 创建 -> (*) 依赖注入 -> 初始化 (*)
context.refresh();
// for (String name : context.getBeanDefinitionNames()) {
// System.out.println(name);
// }
/*
第一个重要方法 findEligibleAdvisors 找到有【资格】的 Advisors
a. 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如下例中的 advisor3
b. 有【资格】的 Advisor 另一部分是高级的, 由本章的主角解析 @Aspect 后获得
*/
AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
List<Advisor> advisors = creator.findEligibleAdvisors(Target2.class, "target2");
/*for (Advisor advisor : advisors) {
System.out.println(advisor);
}*/
/*
第二个重要方法 wrapIfNecessary
a. 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
*/
Object o1 = creator.wrapIfNecessary(new Target1(), "target1", "target1");
System.out.println(o1.getClass());
Object o2 = creator.wrapIfNecessary(new Target2(), "target2", "target2");
System.out.println(o2.getClass());
((Target1) o1).foo(new Target2("ss"));
/*
学到了什么
a. 自动代理后处理器 AnnotationAwareAspectJAutoProxyCreator 会帮我们创建代理
b. 通常代理创建的活在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行
c. 高级的 @Aspect 切面会转换为低级的 Advisor 切面, 理解原理, 大道至简
*/
}
static class Target1 {
public void foo(Target2 ss) {
System.out.println("target1 foo");
}
}
static class Target2 {
public Target2() {
}
public Target2(String ss) {
this.ss = ss;
}
@NonNull
private String ss;
public String getSs() {
return ss;
}
public void setSs(String ss) {
this.ss = ss;
}
public void bar() {
System.out.println("target2 bar");
}
}
@Aspect // 高级切面类
@Order(2)
static class Aspect1 {
@AfterReturning("execution(* foo(*))")
public void before1(JoinPoint joinPoint) {
System.out.println("aspect1 before1..." + (MethodInvocation)joinPoint);
}
@Before("execution(* foo())")
public void before2() {
System.out.println("aspect1 before2...");
}
}
@Configuration
static class Config {
@Bean // 低级切面
// @Order(1) p配置在此地方不生效
public Advisor advisor3(MethodInterceptor advice3) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* foo())");
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice3);
advisor.setOrder(1);
return advisor;
}
@Bean
public MethodInterceptor advice3() {
return invocation -> {
System.out.println("advice3 before...");
Object result = invocation.proceed();
System.out.println("advice3 after...");
return result;
};
}
}
}
收获💡
AnnotationAwareAspectJAutoProxyCreator 的作用
将高级 @Aspect 切面统一为低级 Advisor 切面
在合适的时机创建代理
findEligibleAdvisors 找到有【资格】的 Advisors
有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如本例 A17 中的 advisor3
有【资格】的 Advisor 另一部分是高级的, 由解析 @Aspect 后获得
wrapIfNecessary
它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
它的调用时机通常在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行
演示2 - 代理创建时机
代码参考
org.springframework.aop.framework.autoproxy.A17_1
static class Bean1 {
public void foo() {
}
public Bean1() {
System.out.println("Bean1()");
}
// 取消循环依赖就将该方法注释掉即可
@Autowired public void setBean2(Bean2 bean2) {
System.out.println("Bean1 setBean2(bean2) class is: " + bean2.getClass());
}
@PostConstruct public void init() {
System.out.println("Bean1 init()");
}
}
static class Bean2 {
public Bean2() {
System.out.println("Bean2()");
}
@Autowired public void setBean1(Bean1 bean1) {
System.out.println("Bean2 setBean1(bean1) class is: " + bean1.getClass());
}
@PostConstruct public void init() {
System.out.println("Bean2 init()");
}
}
// 循环依赖演示
注意 “Creating implicit proxy for bean 'bean1'”意思是增强了.
// 无循环依赖
Bean2 setBean1依赖注入Bean1 代理($Bean1)增强后($$EnhancerBySpringCGLIB)的对象
// 工厂方法配置
@Configuration
static class Config {
@Bean // 解析 @Aspect、产生代理
public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
return new AnnotationAwareAspectJAutoProxyCreator();
}
@Bean // 解析 @Autowired
public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
return new AutowiredAnnotationBeanPostProcessor();
}
@Bean // 解析 @PostConstruct
public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
return new CommonAnnotationBeanPostProcessor();
}
@Bean
public Advisor advisor(MethodInterceptor advice) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* foo())");
return new DefaultPointcutAdvisor(pointcut, advice);
}
@Bean
public MethodInterceptor advice() {
return (MethodInvocation invocation) -> {
System.out.println("before...");
return invocation.proceed();
};
}
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
// 主方法调用
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(ConfigurationClassPostProcessor.class);
context.registerBean(Config.class);
context.refresh();
context.close();
// 创建 -> (*) 依赖注入 -> 初始化 (*)
/*
学到了什么
a. 代理的创建时机
1. 初始化之后 (无循环依赖时)
2. 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存
b. 依赖注入与初始化不应该被增强, 仍应被施加于原始对象
*/
}
收获💡??
创建 -> (1.2) 依赖注入 -> 初始化 (1.1)
代理的创建时机
无循环依赖时:初始化之后
有循环依赖时:实例创建后, 依赖注入前 , 并暂存于二级缓存
依赖注入与初始化不应该被增强, 仍 应被施加于原始对象
@Order 、@Priority 与 org.springframework.core.Ordered
基础的应用场景是 配置类中(标注了@Aspect注解的多个类 声明了多个切面 默认的执行顺序是Bean注册的顺序),但我想自定义 切面拦截的顺序。
1.高级切面类的顺序 在@Aspject上标注 @Order注解
@Order 放在类上可以生效。org.aspectj.lang.annotation类下面的注解不是@Bean的子类。所以不能定义拦截的顺序。
2.定义@Configuration (低级切面方法)的顺序。
对于实现了org.springframework.core.Ordered接口的来来说。配置此类的order属性即可。
18) 静态通知调用
高级切面转低级切面类 + 通知统一转换为环绕通知 MethodInterceptor + 创建并执行调用链 (环绕通知s + 目标)
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.*;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class A18 {
static class Aspect {
@Before("execution(* foo())")
public void before1() {
System.out.println("before1");
}
@Before("execution(* foo())")
public void before2() {
System.out.println("before2");
}
public void after() {
System.out.println("after");
}
@AfterReturning("execution(* foo())")
public void afterReturning() {
System.out.println("afterReturning");
}
@AfterThrowing("execution(* foo())")
public void afterThrowing(Exception e) {
System.out.println("afterThrowing " + e.getMessage());
}
@Around("execution(* foo())")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
try {
System.out.println("around...before");
return pjp.proceed();
} finally {
System.out.println("around...after");
}
}
}
static class Target {
public void foo() {
System.out.println("target foo");
}
}
@SuppressWarnings("all")
public static void main(String[] args) throws Throwable {
AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());
// 1. 高级切面转低级切面类
List<Advisor> list = new ArrayList<>();
for (Method method : Aspect.class.getDeclaredMethods()) {
if (method.isAnnotationPresent(Before.class)) {
// 解析切点
String expression = method.getAnnotation(Before.class).value();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
// 通知类
AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
// 切面
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
list.add(advisor);
} else if (method.isAnnotationPresent(AfterReturning.class)) {
// 解析切点
String expression = method.getAnnotation(AfterReturning.class).value();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
// 通知类
AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(method, pointcut, factory);
// 切面
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
list.add(advisor);
} else if (method.isAnnotationPresent(Around.class)) {
// 解析切点
String expression = method.getAnnotation(Around.class).value();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
// 通知类
AspectJAroundAdvice advice = new AspectJAroundAdvice(method, pointcut, factory);
// 切面
Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
list.add(advisor);
}
}
for (Advisor advisor : list) {
// 还要为低级的切面进行排序
System.out.println(advisor);
}
/*
@Before 前置通知会被转换为下面原始的 AspectJMethodBeforeAdvice 形式, 该对象包含了如下信息
a. 通知代码从哪儿来
b. 切点是什么
c. 通知对象如何创建, 本例共用同一个 Aspect 对象
类似的通知还有
1. AspectJAroundAdvice (环绕通知)
2. AspectJAfterReturningAdvice
3. AspectJAfterThrowingAdvice (环绕通知)
4. AspectJAfterAdvice (环绕通知)
*/
// 2. 通知统一转换为环绕通知 MethodInterceptor
/*
其实无论 ProxyFactory 基于哪种方式创建代理, 最后干活(调用 advice)的是一个 MethodInvocation 对象
a. 因为 advisor 有多个, 且一个套一个调用, 因此需要一个调用链对象, 即 MethodInvocation
b. MethodInvocation 要知道 advice 有哪些, 还要知道目标, 调用次序如下
!.将 MethodInvocation 放入当前线程
|-> before1 ----------------------------------- 从当前线程获取 MethodInvocation
| |
| |-> before2 -------------------- | 从当前线程获取 MethodInvocation
| | | |
| | |-> target ------ 目标 advice2 advice1
| | | |
| |-> after2 --------------------- |
| |
|-> after1 ------------------------------------
c. 从上图看出, 环绕通知才适合作为 advice, 因此其他 before、afterReturning 都会被转换成环绕通知
d. 统一转换为环绕通知, 体现的是设计模式中的适配器模式
- 对外是为了方便使用要区分 before、afterReturning
- 对内统一都是环绕通知, 统一用 MethodInterceptor 表示
此步获取所有执行时需要的 advice (静态)
a. 即统一转换为 MethodInterceptor 环绕通知, 这体现在方法名中的 Interceptors 上
b. 适配如下
- MethodBeforeAdviceAdapter 将 @Before AspectJMethodBeforeAdvice 适配为 MethodBeforeAdviceInterceptor
- AfterReturningAdviceAdapter 将 @AfterReturning AspectJAfterReturningAdvice 适配为 AfterReturningAdviceInterceptor
*/
Target target = new Target();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
// !.准备把 MethodInvocation 放入当前线程,需要放在环绕通知的最外层,用于暴露 MethodInvocation 的一个工具类
// 是单例的 使用的私有构造
proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
proxyFactory.addAdvisors(list);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
List<Object> methodInterceptorList = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo"), Target.class);
for (Object o : methodInterceptorList) {
System.out.println(o);
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// 3. 创建并执行调用链 (环绕通知s + 目标)
MethodInvocation methodInvocation = new ReflectiveMethodInvocation(
null, target, Target.class.getMethod("foo"), new Object[0], Target.class, methodInterceptorList
);
methodInvocation.proceed();
/*
学到了什么
a. 无参数绑定的通知如何被调用
b. MethodInvocation 编程技巧: 拦截器、过滤器等等实现都与此类似
c. 适配器模式在 Spring 中的体现
*/
}
}
代理对象调用流程如下(以 JDK 动态代理实现为例)
从 ProxyFactory 获得 Target 和环绕通知链,根据他俩创建 MethodInvocation,简称 mi
首次执行 mi.proceed() 发现有下一个环绕通知,调用它的 invoke(mi)
进入环绕通知1,执行前增强,再次调用 mi.proceed() 发现有下一个环绕通知,调用它的 invoke(mi)
进入环绕通知2,执行前增强,调用 mi.proceed() 发现没有环绕通知,调用 mi.invokeJoinPoint() 执行目标方法
目标方法执行结束,将结果返回给环绕通知2,执行环绕通知2 的后增强
环绕通知2继续将结果返回给环绕通知1,执行环绕通知1 的后增强
环绕通知1返回最终的结果
图中不同颜色对应一次环绕通知或目标的调用起始至终结
模拟 MethodInvocation
/*
模拟调用链过程, 是一个简单的递归过程
1. proceed() 方法调用链中下一个环绕通知
2. 每个环绕通知内部继续调用 proceed()
3. 调用到没有更多通知了, 就调用目标方法
*/
public class A18_1 {
static class Target {
public void foo() {
System.out.println("Target.foo()");
}
}
static class Advice1 implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Advice1.before()");
Object result = invocation.proceed();// 调用下一个通知或目标
System.out.println("Advice1.after()");
return result;
}
}
static class Advice2 implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Advice2.before()");
Object result = invocation.proceed();// 调用下一个通知或目标
System.out.println("Advice2.after()");
return result;
}
}
static class MyInvocation implements MethodInvocation {
private Object target; // 1
private Method method;
private Object[] args;
List<MethodInterceptor> methodInterceptorList; // 2
private int count = 1; // 调用次数
public MyInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> methodInterceptorList) {
this.target = target;
this.method = method;
this.args = args;
this.methodInterceptorList = methodInterceptorList;
}
@Override
public Method getMethod() {
return method;
}
@Override
public Object[] getArguments() {
return args;
}
@Override
public Object proceed() throws Throwable { // 调用每一个环绕通知, 调用目标
if (count > methodInterceptorList.size()) {
// 调用目标, 返回并结束递归
return method.invoke(target, args);
}
// 逐一调用通知, count + 1
MethodInterceptor methodInterceptor = methodInterceptorList.get(count++ - 1);
return methodInterceptor.invoke(this);
}
@Override
public Object getThis() {
return target;
}
@Override
public AccessibleObject getStaticPart() {
return method;
}
}
public static void main(String[] args) throws Throwable {
Target target = new Target();
List<MethodInterceptor> list = List.of(
new Advice1(),
new Advice2()
);
MyInvocation invocation = new MyInvocation(target, Target.class.getMethod("foo"), new Object[0], list);
invocation.proceed();
}
}
aspectj.lang.annotation
注解介绍: Spring AOP切点表达式用法总结 - 爱宝贝丶 - 博客园 (cnblogs.com)
切面形参介绍:@Aspect 切面注解使用 - 秃了也变强了 - 博客园 (cnblogs.com)
拦截器执行的顺序:
try {
Object result = null;
try {
System.out.println("@Around通知start");
System.out.println("@Before通知!");
result = service4.say("路人");
System.out.println("@Around绕通知end");
return result;
} finally {
System.out.println("@After通知!");
}
System.out.println("@AfterReturning通知!");
return retVal;
} catch (Throwable ex) {
System.out.println("@AfterThrowing通知!");
//继续抛出异常
throw ex;
}