代理增强方式 aspectj编译器增强 先看一组例子:
pom.xml
文件中增加插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <plugin > <groupId > org.codehaus.mojo</groupId > <artifactId > aspectj-maven-plugin</artifactId > <version > 1.14.0</version > <configuration > <complianceLevel > 1.8</complianceLevel > <source > 8</source > <target > 8</target > <showWeaveInfo > true</showWeaveInfo > <verbose > true</verbose > <Xlint > ignore</Xlint > <encoding > UTF-8</encoding > </configuration > <executions > <execution > <goals > <goal > compile</goal > <goal > test-compile</goal > </goals > </execution > </executions > </plugin >
编写com.itheima.service.MyService
类:
1 2 3 4 5 6 7 8 9 @Service public class MyService { private static final Logger log = LoggerFactory.getLogger(MyService.class); public static void foo () { log.debug("foo()" ); } }
编写com.itheima.aop.MyAspect
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Aspect public class MyAspect { private static final Logger log = LoggerFactory.getLogger(MyAspect.class); @Before("execution(* com.itheima.service.MyService.foo())") public void before () { log.debug("before()" ); } }
MyAspect
类代理了MyService
类,增加了前置通知。
编写启动类com.itheima.A09
:
1 2 3 4 5 6 7 8 9 @SpringBootApplication public class A09 { private static final Logger log = LoggerFactory.getLogger(A09.class); public static void main (String[] args) { new MyService ().foo(); } }
运行启动类,查看控制台:
1 2 11:35:42.441 [main] DEBUG com.itheima.aop.MyAspect - before() 11:35:42.444 [main] DEBUG com.itheima.service.MyService - foo()
aspectj
编译器增强时在编译阶段直接修改类文件 ,并且不需要依赖spring
容器,我们查看被改写的类文件:
1 2 3 4 5 6 7 8 9 10 11 12 @Service public class MyService { private static final Logger log = LoggerFactory.getLogger(MyService.class); public MyService () { } public static void foo () { MyAspect.aspectOf().before(); log.debug("foo()" ); } }
发现直接在目标方法前加上了我们的前置增强方法。
当jdk
代理和cglib
代理都不能使用时,可以考虑使用此方式实现代理。
agent类加载增强 先看一组例子:
编写com.itheima.service.MyService
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Service public class MyService { private static final Logger log = LoggerFactory.getLogger(MyService.class); final public void foo () { log.debug("foo()" ); this .bar(); } public void bar () { log.debug("bar()" ); } }
编写com.itheima.aop.MyAspect
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Aspect public class MyAspect { private static final Logger log = LoggerFactory.getLogger(MyAspect.class); @Before("execution(* com.itheima.service.MyService.*())") public void before () { log.debug("before()" ); } }
MyAspect
类代理了MyService
类,并对所有方法增加了前置通知。
编写启动类com.itheima.A10
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @SpringBootApplication public class A10 { private static final Logger log = LoggerFactory.getLogger(A10.class); public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(A10.class, args); MyService service = context.getBean(MyService.class); log.debug("service class: {}" , service.getClass()); service.foo(); context.close(); } }
agent
类增强是在类加载阶段修改类文件 进行的增强,运行时需要加上虚拟机参数:
1 -javaagent:C:/Users/WolfMan/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspectjweaver-1.9.7.jar
运行启动类,查看控制台:
1 2 3 4 2023-03-27 14:49:59.773 DEBUG 30220 --- [ main] com.itheima.aop.MyAspect : before() 2023-03-27 14:49:59.773 DEBUG 30220 --- [ main] com.itheima.service.MyService : foo() 2023-03-27 14:49:59.773 DEBUG 30220 --- [ main] com.itheima.aop.MyAspect : before() 2023-03-27 14:49:59.773 DEBUG 30220 --- [ main] com.itheima.service.MyService : bar()
这种代理方式突破了普通代理的限制,即在一个方法内调用另外的方法,这两个方法都被代理了,而普通的代理只能代理被调用的方法。
打开arthas
,连接目标进程,使用jad
命令反编译MyService
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.itheima.service;import com.itheima.aop.MyAspect;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Service;@Service public class MyService { private static final Logger log = LoggerFactory.getLogger(MyService.class); public final void foo () { MyAspect.aspectOf().before(); log.debug("foo()" ); this .bar(); } public void bar () { MyAspect.aspectOf().before(); log.debug("bar()" ); } }
发现在方法前插入了我们增强的方法。
jdk代理增强 演示代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class JdkProxyDemo { interface Foo { void foo () ; } static final class Target implements Foo { public void foo () { System.out.println("target foo" ); } } public static void main (String[] param) throws IOException { Target target = new Target (); ClassLoader loader = JdkProxyDemo.class.getClassLoader(); Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class []{Foo.class}, (p, method, args) -> { System.out.println("before..." ); Object result = method.invoke(target, args); System.out.println("after...." ); return result; }); System.out.println(proxy.getClass()); proxy.foo(); System.in.read(); } }
运行main()
方法,查看控制台:
1 2 3 4 class com.itheima.a11.$Proxy0 before... target foo after....
发现对象被代理了,打印出我们真实调用的对象实际上是一个代理类对象。
invoke
方法的参数:
Object
:代表代理类自身
Method
:代表代理类正在执行的方法
Object[]
:代表正在执行方法传入的参数
jdk
代理的特点:
被代理对象与代理对象为兄弟关系,都实现了父接口
被代理对象如果被final修饰没有影响
cglib代理增强 实例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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("before..." ); Object result = method.invoke(target, args); System.out.println("after..." ); return result; }); proxy.foo(); } }
运行main()
方法,查看控制台:
1 2 3 before... target foo after...
MethodInterceptor
参数含义:
Object
:代表代理类自身
Method
:代表代理类正在执行的方法
Object[]
:代表正在执行方法传入的参数
MethodProxy
:一个方法对象,提供更多功能
cgilib
代理的特点:
被代理对象与代理对象为父子关系,代理对象继承了被代理对象
被代理对象或者方法为final都不能使用cglib代理
MethodInterceptor
参数中的methodProxy
有两个方法可以避免反射调用:
methodProxy.invoke(target, args)
:内部没有用反射, 需要目标(spring使用的这种方式)
methodProxy.invokeSuper(p, args)
:内部没有用反射, 需要代理
实例使用:
1 2 Object result = methodProxy.invoke(target, args); Object result = methodProxy.invokeSuper(p, args);
jdk动态代理原理 模拟jdk动态代理 代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 interface Foo { void foo () ; int bar () ; } interface InvocationHandler { Object invoke (Object proxy, Method method, Object[] args) throws Throwable; } class Target implements Foo { public void foo () { System.out.println("target foo" ); } @Override public int bar () { System.out.println("target bar" ); return 100 ; } } public class $Proxy0 implements Foo { static Method foo; static Method bar; static { try { foo = Foo.class.getMethod("foo" ); bar = Foo.class.getMethod("bar" ); } catch (NoSuchMethodException e) { throw new NoSuchMethodError (e.getMessage()); } } InvocationHandler h; public $Proxy0(InvocationHandler h) { this .h = h; } @Override public void foo () { try { 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); } } } public class A12 { public static void main (String[] param) { Foo proxy = new $Proxy0 (new InvocationHandler () { @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before..." ); return method.invoke(new Target (), args); } }); proxy.foo(); proxy.bar(); } }
模拟jdk动态代理思路:
方法重写可以增强逻辑, 只不过这增强逻辑 千变万化, 不能写死在代理内部
通过接口回调将增强逻辑 置于代理类之外
配合接口方法反射(也是多态),就可以再联动调用目标方法
jdk动态代理源码 打开arthas:
1 C:/Path/jdk1.8.0_152/bin/java -jar arthas-boot.jar
连接进程,使用jad
命令查看运行时的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 package com.itheima.a11;import com.itheima.a11.JdkProxyDemo;import java.lang.invoke.MethodHandles;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 JdkProxyDemo .Foo { private static final Method m0; private static final Method m1; private static final Method m2; private static final Method m3; public $Proxy0(InvocationHandler invocationHandler) { super (invocationHandler); } static { ClassLoader classLoader = $Proxy0.class.getClassLoader(); try { m0 = Class.forName("java.lang.Object" , false , classLoader).getMethod("hashCode" , new Class [0 ]); m1 = Class.forName("java.lang.Object" , false , classLoader).getMethod("equals" , Class.forName("java.lang.Object" , false , classLoader)); m2 = Class.forName("java.lang.Object" , false , classLoader).getMethod("toString" , new Class [0 ]); m3 = Class.forName("com.itheima.a11.JdkProxyDemo$Foo" , false , classLoader).getMethod("foo" , new Class [0 ]); return ; } catch (NoSuchMethodException noSuchMethodException) { throw new NoSuchMethodError (noSuchMethodException.getMessage()); } catch (ClassNotFoundException classNotFoundException) { throw new NoClassDefFoundError (classNotFoundException.getMessage()); } } 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 hashCode () { try { return (Integer)this .h.invoke(this , m0, null ); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException (throwable); } } public final void foo () { try { this .h.invoke(this , m3, null ); return ; } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException (throwable); } } private static MethodHandles.Lookup proxyClassLookup (MethodHandles.Lookup lookup) throws IllegalAccessException { if (lookup.lookupClass() == Proxy.class && lookup.hasFullPrivilegeAccess()) { return MethodHandles.lookup(); } throw new IllegalAccessException (lookup.toString()); } }
jdk直接生成字节码使用的技术是ASM,接下来演示ASM生成的字节码。
在idea中安装ASM Bytecode Viewer Support Kotlin
插件,编写以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public interface Foo { public void foo () ; } public class $Proxy0 extends Proxy implements Foo { static Method foo; public $Proxy0(InvocationHandler h) { super (h); } public void foo () { try { this .h.invoke(this , foo, null ); } catch (Throwable var2) { throw new UndeclaredThrowableException (var2); } } static { try { foo = Foo.class.getMethod("foo" ); } catch (NoSuchMethodException var1) { throw new NoSuchMethodError (var1.getMessage()); } } }
编译这两个类,在$Proxy0
中右键ASM Bytecode Viewer
,选择ASMified
选项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 package asm.com.itheima;import org.objectweb.asm.AnnotationVisitor;import org.objectweb.asm.Attribute;import org.objectweb.asm.ClassReader;import org.objectweb.asm.ClassWriter;import org.objectweb.asm.ConstantDynamic;import org.objectweb.asm.FieldVisitor;import org.objectweb.asm.Handle;import org.objectweb.asm.Label;import org.objectweb.asm.MethodVisitor;import org.objectweb.asm.Opcodes;import org.objectweb.asm.Type;import org.objectweb.asm.TypePath;public class $Proxy0Dump implements Opcodes { public static byte [] dump() throws Exception { ClassWriter classWriter = new ClassWriter (0 ); FieldVisitor fieldVisitor; MethodVisitor methodVisitor; AnnotationVisitor annotationVisitor0; classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "com/itheima/$Proxy0" , null , "java/lang/reflect/Proxy" , new String []{"com/itheima/Foo" }); { fieldVisitor = classWriter.visitField(ACC_STATIC, "foo" , "Ljava/lang/reflect/Method;" , null , null ); fieldVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>" , "(Ljava/lang/reflect/InvocationHandler;)V" , null , null ); methodVisitor.visitCode(); methodVisitor.visitVarInsn(ALOAD, 0 ); methodVisitor.visitVarInsn(ALOAD, 1 ); methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/Proxy" , "<init>" , "(Ljava/lang/reflect/InvocationHandler;)V" , false ); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(2 , 2 ); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "foo" , "()V" , null , null ); methodVisitor.visitCode(); Label label0 = new Label (); Label label1 = new Label (); Label label2 = new Label (); methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/lang/Throwable" ); methodVisitor.visitLabel(label0); methodVisitor.visitVarInsn(ALOAD, 0 ); methodVisitor.visitFieldInsn(GETFIELD, "com/itheima/$Proxy0" , "h" , "Ljava/lang/reflect/InvocationHandler;" ); methodVisitor.visitVarInsn(ALOAD, 0 ); methodVisitor.visitFieldInsn(GETSTATIC, "com/itheima/$Proxy0" , "foo" , "Ljava/lang/reflect/Method;" ); methodVisitor.visitInsn(ACONST_NULL); methodVisitor.visitMethodInsn(INVOKEINTERFACE, "java/lang/reflect/InvocationHandler" , "invoke" , "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;" , true ); methodVisitor.visitInsn(POP); methodVisitor.visitLabel(label1); Label label3 = new Label (); methodVisitor.visitJumpInsn(GOTO, label3); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ASTORE, 1 ); methodVisitor.visitTypeInsn(NEW, "java/lang/reflect/UndeclaredThrowableException" ); methodVisitor.visitInsn(DUP); methodVisitor.visitVarInsn(ALOAD, 1 ); methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/reflect/UndeclaredThrowableException" , "<init>" , "(Ljava/lang/Throwable;)V" , false ); methodVisitor.visitInsn(ATHROW); methodVisitor.visitLabel(label3); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(4 , 2 ); methodVisitor.visitEnd(); } { methodVisitor = classWriter.visitMethod(ACC_STATIC, "<clinit>" , "()V" , null , null ); methodVisitor.visitCode(); Label label0 = new Label (); Label label1 = new Label (); Label label2 = new Label (); methodVisitor.visitTryCatchBlock(label0, label1, label2, "java/lang/NoSuchMethodException" ); methodVisitor.visitLabel(label0); methodVisitor.visitLdcInsn(Type.getType("Lcom/itheima/Foo;" )); methodVisitor.visitLdcInsn("foo" ); methodVisitor.visitInsn(ICONST_0); methodVisitor.visitTypeInsn(ANEWARRAY, "java/lang/Class" ); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class" , "getMethod" , "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;" , false ); methodVisitor.visitFieldInsn(PUTSTATIC, "com/itheima/$Proxy0" , "foo" , "Ljava/lang/reflect/Method;" ); methodVisitor.visitLabel(label1); Label label3 = new Label (); methodVisitor.visitJumpInsn(GOTO, label3); methodVisitor.visitLabel(label2); methodVisitor.visitVarInsn(ASTORE, 0 ); methodVisitor.visitTypeInsn(NEW, "java/lang/NoSuchMethodError" ); methodVisitor.visitInsn(DUP); methodVisitor.visitVarInsn(ALOAD, 0 ); methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/NoSuchMethodException" , "getMessage" , "()Ljava/lang/String;" , false ); methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/NoSuchMethodError" , "<init>" , "(Ljava/lang/String;)V" , false ); methodVisitor.visitInsn(ATHROW); methodVisitor.visitLabel(label3); methodVisitor.visitInsn(RETURN); methodVisitor.visitMaxs(3 , 1 ); methodVisitor.visitEnd(); } classWriter.visitEnd(); return classWriter.toByteArray(); } }
我们可以使用此类生成代码:
1 2 3 4 5 6 7 8 9 public class TestProxy { public static void main (String[] args) throws Exception { byte [] dump = $Proxy0Dump.dump(); FileOutputStream os = new FileOutputStream ("$Proxy0.class" ); os.write(dump, 0 , dump.length); os.close(); } }
在项目目录下生成文件$Proxy0.class
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.itheima;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public class $Proxy0 extends Proxy implements Foo { static Method foo; public $Proxy0(InvocationHandler h) { super (h); } public void foo () { try { this .h.invoke(this , foo, (Object[])null ); } catch (Throwable var2) { throw new UndeclaredThrowableException (var2); } } static { try { foo = Foo.class.getMethod("foo" ); } catch (NoSuchMethodException var1) { throw new NoSuchMethodError (var1.getMessage()); } } }
我们也可以使用$Proxy0Dump
类调用方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class TestProxy { public static void main (String[] args) throws Exception { byte [] dump = $Proxy0Dump.dump(); ClassLoader loader = new ClassLoader () { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { return super .defineClass(name, dump, 0 , dump.length); } }; Class<?> proxyClass = loader.loadClass("com.itheima.$Proxy0" ); Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class); Foo proxy = (Foo) constructor.newInstance(new InvocationHandler () { @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before..." ); System.out.println("调用目标" ); return null ; } }); proxy.foo(); } }
运行main()方法,查看控制台:
jdk反射优化 编写测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.lang.reflect.Field;import java.lang.reflect.Method;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(); } 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" ); } }
运行启动类,查看控制台输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 1 :null 1 :foo2 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 2 :foo3 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 3 :foo4 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 4 :foo5 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 5 :foo6 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 6 :foo7 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 7 :foo8 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 8 :foo9 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 9 :foo10 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 10 :foo11 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 11 :foo12 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 12 :foo13 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 13 :foo14 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 14 :foo15 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 15 :foo16 :jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2 16 :foo17 :jdk.internal.reflect.GeneratedMethodAccessor2@2d38eb89 17 :foo
我们发现前面16次调用都是使用jdk.internal.reflect.NativeMethodAccessorImpl@5b37e0d2
,这个实现是使用java本地api实现的,性能比较低。
我们可以使用arthas查看jdk.internal.reflect.GeneratedMethodAccessor2
的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package jdk.internal.reflect;import com.itheima.a12.TestMethodInvoke;import java.lang.reflect.InvocationTargetException;import jdk.internal.reflect.MethodAccessorImpl;public class GeneratedMethodAccessor2 extends MethodAccessorImpl { public Object invoke (Object object, Object[] objectArray) throws InvocationTargetException { char c; block9: { if (objectArray.length != 1 ) { throw new IllegalArgumentException (); } Object object2 = objectArray[0 ]; if (object2 instanceof Byte) { c = ((Byte)object2).byteValue(); break block9; } if (object2 instanceof Character) { c = ((Character)object2).charValue(); break block9; } if (object2 instanceof Short) { c = (char )((Short)object2).shortValue(); break block9; } if (object2 instanceof Integer) { c = (char )((Integer)object2).intValue(); break block9; } throw new IllegalArgumentException (); } try { TestMethodInvoke.foo((int )c); return null ; } catch (Throwable throwable) { throw new InvocationTargetException (throwable); } catch (ClassCastException | NullPointerException runtimeException) { throw new IllegalArgumentException (super .toString()); } } }
我们发现jdk在运行时直接生成了jdk.internal.reflect.GeneratedMethodAccessor2
类,然后直接调用其方法,避免了反射调用的性能损耗。缺点是每个方法都需要生成一个代理类,而cglib是一个类所有方法的代理生成两个代理类进行直接调用。
cglib动态代理原理 模拟cglib动态代理 代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 public class Target { public void save () { System.out.println("save()" ); } public void save (int i) { System.out.println("save(int)" ); } public void save (long j) { System.out.println("save(long)" ); } } public class Proxy extends Target { private MethodInterceptor methodInterceptor; public void setMethodInterceptor (MethodInterceptor methodInterceptor) { this .methodInterceptor = methodInterceptor; } static Method save0; static Method save1; static Method save2; static MethodProxy save0Proxy; static MethodProxy save1Proxy; static MethodProxy save2Proxy; static { try { save0 = Target.class.getMethod("save" ); save1 = Target.class.getMethod("save" , int .class); save2 = Target.class.getMethod("save" , long .class); save0Proxy = MethodProxy.create(Target.class, Proxy.class, "()V" , "save" , "saveSuper" ); save1Proxy = MethodProxy.create(Target.class, Proxy.class, "(I)V" , "save" , "saveSuper" ); save2Proxy = MethodProxy.create(Target.class, Proxy.class, "(J)V" , "save" , "saveSuper" ); } catch (NoSuchMethodException e) { throw new NoSuchMethodError (e.getMessage()); } } public void saveSuper () { super .save(); } public void saveSuper (int i) { super .save(i); } public void saveSuper (long j) { super .save(j); } @Override public void save () { try { methodInterceptor.intercept(this , save0, new Object [0 ], save0Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException (e); } } @Override public void save (int i) { try { methodInterceptor.intercept(this , save1, new Object []{i}, save1Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException (e); } } @Override public void save (long j) { try { methodInterceptor.intercept(this , save2, new Object []{j}, save2Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException (e); } } } public class A13 { public static void main (String[] args) { Proxy proxy = new Proxy (); Target target = new Target (); proxy.setMethodInterceptor(new MethodInterceptor () { @Override public Object intercept (Object p, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before..." ); return method.invoke(target, args); } }); proxy.save(); proxy.save(1 ); proxy.save(2L ); } }
运行启动类,查看控制台:
1 2 3 4 5 6 before... save() before... save(int) before... save(long)
MethodProxy原理 methodProxy
的invoke()
方法和invokeSuper()
方法都可以避免反射调用,以提高动态代理的性能,接下来我们介绍这两种方法。
invoke() cglib在调用invoke()
方法和invokeSuper()
方法的时候会生成两个代理类,这两个代理类都继承了org.springframework.cglib.reflect.FastClass
,这两个代理类中的一些关键方法就避免了反射。
其中有两个关键抽象方法:
1 2 public abstract int getIndex (Signature var1) ;public abstract Object invoke (int var1, Object var2, Object[] var3) throws InvocationTargetException;
接下来模拟method.invoke()
方法的实现,取名叫TargetFastClass
,主要实现以上两个抽象方法的功能,TargetFastClass
会在Proxy
调用MethodProxy.create()
的时候创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public class TargetFastClass { static Signature s0 = new Signature ("save" , "()V" ); static Signature s1 = new Signature ("save" , "(I)V" ); static Signature s2 = new Signature ("save" , "(J)V" ); public int getIndex (Signature signature) { if (s0.equals(signature)) { return 0 ; } else if (s1.equals(signature)) { return 1 ; } else if (s2.equals(signature)) { return 2 ; } return -1 ; } public Object invoke (int index, Object target, Object[] args) { if (index == 0 ) { ((Target) target).save(); return null ; } else if (index == 1 ) { ((Target) target).save((int ) args[0 ]); return null ; } else if (index == 2 ) { ((Target) target).save((long ) args[0 ]); return null ; } else { throw new RuntimeException ("无此方法" ); } } public static void main (String[] args) { TargetFastClass fastClass = new TargetFastClass (); int index = fastClass.getIndex(new Signature ("save" , "(I)V" )); fastClass.invoke(index, new Target (), new Object []{100 }); } }
method.invoke()
调用流程:
当proxy被创建时,会初始化方法信息 ,创建MethodProxy
调用method.invoke(target, args)
时,会先根据签名获取index
根据传入的index,target,args参数调用TargetFastClass
的invoke()
方法
invokeSuper() 接下来模拟method.invoke()
方法的实现,取名叫ProxyFastClass
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 public class ProxyFastClass { static Signature s0 = new Signature ("saveSuper" , "()V" ); static Signature s1 = new Signature ("saveSuper" , "(I)V" ); static Signature s2 = new Signature ("saveSuper" , "(J)V" ); public int getIndex (Signature signature) { if (s0.equals(signature)) { return 0 ; } else if (s1.equals(signature)) { return 1 ; } else if (s2.equals(signature)) { return 2 ; } return -1 ; } public Object invoke (int index, Object proxy, Object[] args) { if (index == 0 ) { ((Proxy) proxy).saveSuper(); return null ; } else if (index == 1 ) { ((Proxy) proxy).saveSuper((int ) args[0 ]); return null ; } else if (index == 2 ) { ((Proxy) proxy).saveSuper((long ) args[0 ]); return null ; } else { throw new RuntimeException ("无此方法" ); } } public static void main (String[] args) { ProxyFastClass fastClass = new ProxyFastClass (); int index = fastClass.getIndex(new Signature ("saveSuper" , "()V" )); System.out.println(index); fastClass.invoke(index, new Proxy (), new Object [0 ]); } }
ProxyFastClass
的实现和TargetFastClass
类似,只不过传入的参数是代理类本身,并且在invoke()
方法中调用的是invokeSuper()
方法(原始方法)。
method.invokeSuper()
调用流程:
当proxy被创建时,会初始化方法信息 ,创建MethodProxy
调用method.invoke(proxy, args)
时,会先根据签名获取index
根据传入的proxy
,target
,args
参数调用ProxyFastClass
的invokeSuper()
方法
jdk与cglib动态代理对比:
jdk
动态代理需要先预热16次,再进行优化,并且每个方法会生成一个代理类
cglib
动态代理直接就可以避免反射调用,并且一个类对应两个代理类(FastClass
实现)
jdk和cglib的统一 spring的代理选择规则 aspect
切面与advisor
切面的区别:
aspect = 通知1(advice) + 切点1(pointcut)
,一个aspect类中可以定义多个通知和切点。
advisor
是更细粒度的切面,包含一个通知和切点
aspect
最终生效解析之前会被拆解成多个advisor
使用代理增强的步骤:
备好切点
备好通知
备好切面
创建代理
切点在spring中是用org.springframework.aop.Pointcut
来表示:
1 2 3 4 5 6 7 public interface Pointcut { Pointcut TRUE = TruePointcut.INSTANCE; ClassFilter getClassFilter () ; MethodMatcher getMethodMatcher () ; }
可以看到比较常用的实现:
比较重要的通知org.aopalliance.intercept.MethodInterceptor
:
1 2 3 4 5 @FunctionalInterface public interface MethodInterceptor extends Interceptor { @Nullable Object invoke (@Nonnull MethodInvocation invocation) throws Throwable; }
代码演示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 public class A15 { public static void main (String[] args) { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut (); pointcut.setExpression("execution(* foo())" ); MethodInterceptor advice = invocation -> { System.out.println("before..." ); Object result = invocation.proceed(); System.out.println("after..." ); return result; }; DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor (pointcut, advice); Target2 target = new Target2 (); ProxyFactory factory = new ProxyFactory (); factory.setTarget(target); factory.addAdvisor(advisor); factory.setInterfaces(target.getClass().getInterfaces()); factory.setProxyTargetClass(false ); Target2 proxy = (Target2) factory.getProxy(); System.out.println(proxy.getClass()); proxy.foo(); proxy.bar(); } 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" ); } } }
spring的代理选择规则
ProxyFactory
的间接父类中ProxyConfig
有proxyTargetClass
字段:
proxyTargetClass = false
,目标实现了接口, 用 jdk 实现
proxyTargetClass = false
,目标没有实现接口, 用 cglib 实现
proxyTargetClass = true
, 总是使用 cglib 实现
底层的切点实现 介绍切点匹配的方法,编写两个示例类:
1 2 3 4 5 6 7 static class T1 { @Transactional public void foo () { } public void bar () { } }
创建启动类,根据表达式 切入:
1 2 3 4 5 6 7 8 public class A16 { public static void main (String[] args) throws NoSuchMethodException { AspectJExpressionPointcut pt1 = new AspectJExpressionPointcut (); pt1.setExpression("execution(* bar())" ); System.out.println(pt1.matches(T1.class.getMethod("foo" ), T1.class)); System.out.println(pt1.matches(T1.class.getMethod("bar" ), T1.class)); } }
运行启动类,查看控制台:
foo()
方法没有被表达式匹配,bar()
成功匹配。
创建启动类,根据注解 切入:
1 2 3 4 5 6 7 8 public class A16 { public static void main (String[] args) throws NoSuchMethodException { AspectJExpressionPointcut pt2 = new AspectJExpressionPointcut (); pt2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)" ); System.out.println(pt2.matches(T1.class.getMethod("foo" ), T1.class)); System.out.println(pt2.matches(T1.class.getMethod("bar" ), T1.class)); } }
运行启动类,查看控制台:
foo()
方法被注解匹配,bar()
没有被匹配。
@Transactional注解并不是使用AspectJExpressionPointcut这种方式来实现的
@Transactional
注解有多种使用方式:
加在方法上
1 2 3 4 5 static class T1 { @Transactional public void foo () { } }
加在类上
1 2 3 4 5 @Transactional static class T2 { public void foo () { } }
加载接口上,实现类实现了该接口的方法将会生效
1 2 3 4 5 6 7 8 @Transactional interface I3 { void foo () ; } static class T3 implements I3 { public void foo () { } }
AspectJExpressionPointcut
没法处理@Transactional
注解的这些场景,因此我们这里模拟解析@Transactional
注解的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class A16 { public static void main (String[] args) throws NoSuchMethodException { StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut () { @Override public boolean matches (Method method, Class<?> targetClass) { MergedAnnotations annotations = MergedAnnotations.from(method); if (annotations.isPresent(Transactional.class)) { return true ; } 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)); System.out.println(pt3.matches(T1.class.getMethod("bar" ), T1.class)); System.out.println(pt3.matches(T2.class.getMethod("foo" ), T2.class)); System.out.println(pt3.matches(T3.class.getMethod("foo" ), T3.class)); } static class T1 { @Transactional public void foo () { } public void bar () { } } @Transactional static class T2 { public void foo () { } } @Transactional interface I3 { void foo () ; } static class T3 implements I3 { public void foo () { } } }
运行启动类,查看控制台:
底层的切面实现 准备代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 package org.springframework.aop.framework.autoproxy;import org.aopalliance.intercept.MethodInterceptor;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 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); context.refresh(); for (String name : context.getBeanDefinitionNames()) { System.out.println(name); } } static class Target1 { public void foo () { System.out.println("target1 foo" ); } } static class Target2 { public void bar () { System.out.println("target2 bar" ); } } @Aspect static class Aspect1 { @Before("execution(* foo())") public void before1 () { System.out.println("aspect1 before1..." ); } @Before("execution(* foo())") public void before2 () { System.out.println("aspect1 before2..." ); } } @Configuration static class Config { @Bean public Advisor advisor3 (MethodInterceptor advice3) { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut (); pointcut.setExpression("execution(* foo())" ); DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor (pointcut, advice3); return advisor; } @Bean public MethodInterceptor advice3 () { return invocation -> { System.out.println("advice3 before..." ); Object result = invocation.proceed(); System.out.println("advice3 after..." ); return result; }; } } }
运行启动类,查看控制台:
1 2 3 4 5 aspect1 config org.springframework.context.annotation.ConfigurationClassPostProcessor advisor3 advice3
底层切面实现 底层切面实现用的是AnnotationAwareAspectJAutoProxyCreator
,AnnotationAwareAspectJAutoProxyCreator
是一个Bean后处理器,它有两个作用:
找到容器中所有的切面,如果是@Aspect
这种高级切面,会将其转换为advisor
低级切面
根据找到的切面创建代理对象
查看其类图:
我们发现它实现了BeanPostProcessor
接口,对Bean
进行了增强。AnnotationAwareAspectJAutoProxyCreator
主要是在Bean
依赖注入 之前以及初始化 之后进行了增强。它有两个比较重要的方法:
findEligibleAdvisors()
:找到有资格的切面类,主要找的是advisor
,如果是高级切面,会将其转换为低级切面
wrapIfNecessary()
:针对符合要求的切面类创建代理
这两个方法都被protected
方法修饰,因此我们把测试类放在org.springframework.aop.framework.autoproxy
包内。
findEligibleAdvisors() 此方法的功能是:根据给定的目标类型,查找与目标类型相匹配的所有切面。
添加代码进行测试:
首先将AnnotationAwareAspectJAutoProxyCreator
类注入spring
容器中:
1 context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
获取AnnotationAwareAspectJAutoProxyCreator
,调用findEligibleAdvisors()
方法,并打印切面
1 2 3 4 5 AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);List<Advisor> advisors = creator.findEligibleAdvisors(Target1.class, "target1" ); for (Advisor advisor : advisors) { System.out.println(advisor); }
查看控制台:
1 2 3 4 5 6 7 org.springframework.aop.interceptor.ExposeInvocationInterceptor.ADVISOR InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [public void org.springframework.aop.framework.autoproxy.A17$Aspect1.before1()]; perClauseKind=SINGLETON InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [public void org.springframework.aop.framework.autoproxy.A17$Aspect1.before2()]; perClauseKind=SINGLETON org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.framework.autoproxy.A17$Config$$Lambda$117 /0x0000000800d64fc0 @558bdf1f]
wrapIfNecessary() 此方法的功能是:是否有必要为我们的目标创建代理。
思路很简单:调用findEligibleAdvisors()
方法,如果返回值为空,那么说明不需要为这个类创建代理,反之需要创建单例。
添加代码进行测试:
1 2 3 4 5 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();
运行启动类,查看控制台:
1 2 3 4 5 6 7 class org .springframework.aop.framework.autoproxy.A17$Target1$$EnhancerBySpringCGLIB$$253983d3class org .springframework.aop.framework.autoproxy.A17$Target2aspect1 before1... aspect1 before2... advice3 before... target1 foo advice3 after...
我们发现Target1
类已经被代理,调用foo()
方法也能看到对方法的增强。
代理对象创建的时机 代理对象的创建位置在依赖注入之前或者是在初始化之后。
暂时无法在飞书文档外展示此内容
准备示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 public class A17_1 { public static void main (String[] args) { GenericApplicationContext context = new GenericApplicationContext (); context.registerBean(ConfigurationClassPostProcessor.class); context.registerBean(Config.class); context.refresh(); context.close(); } @Configuration static class Config { @Bean public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator () { return new AnnotationAwareAspectJAutoProxyCreator (); } @Bean public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor () { return new AutowiredAnnotationBeanPostProcessor (); } @Bean 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 (); } } static class Bean1 { public void foo () { } public Bean1 () { System.out.println("Bean1()" ); } @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()" ); } } }
上述代码Bean2依赖注入了Bean1。
查看控制台:
1 2 3 4 5 6 7 8 9 [INFO ] 21:59:12.415 [main] o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.aop.framework.autoproxy.A17_1$Config' of type [org.springframework.aop.framework.autoproxy.A17_1$Config$$EnhancerBySpringCGLIB$$4ebf3912] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) [TRACE] 21:59:12.474 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Did not attempt to auto-proxy infrastructure class [org.springframework.aop.Advisor] [TRACE] 21:59:12.476 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Did not attempt to auto-proxy infrastructure class [org.aopalliance.intercept.MethodInterceptor] Bean1() Bean1 init() [TRACE] 21:59:12.575 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Creating implicit proxy for bean 'bean1' with 0 common interceptors and 2 specific interceptors Bean2() Bean2 setBean1(bean1) class is: class org.springframework.aop.framework.autoproxy.A17_1$Bean1$$EnhancerBySpringCGLIB$$2d106fac Bean2 init()
发现Bean1
的代理对象是在初始化之后被创建的。
更改Bean1
类,使其与Bean2
循环依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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()" ); } }
查看控制台:
1 2 3 4 5 6 7 8 9 10 [INFO ] 22:02:35.788 [main] o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.aop.framework.autoproxy.A17_1$Config' of type [org.springframework.aop.framework.autoproxy.A17_1$Config$$EnhancerBySpringCGLIB$$4ebf3912] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) [TRACE] 22:02:35.850 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Did not attempt to auto-proxy infrastructure class [org.springframework.aop.Advisor] [TRACE] 22:02:35.852 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Did not attempt to auto-proxy infrastructure class [org.aopalliance.intercept.MethodInterceptor] Bean1() Bean2() [TRACE] 22:02:36.015 [main] o.s.a.a.a.AnnotationAwareAspectJAutoProxyCreator - Creating implicit proxy for bean 'bean1' with 0 common interceptors and 2 specific interceptors Bean2 setBean1(bean1) class is: class org.springframework.aop.framework.autoproxy.A17_1$Bean1$$EnhancerBySpringCGLIB$$2741d750 Bean2 init() Bean1 setBean2(bean2) class is: class org.springframework.aop.framework.autoproxy.A17_1$Bean2 Bean1 init()
发现Bean1
代理对象的创建提前在Bean1
初始化之前了,这是因为Bean2
需要注入的使Bean1
的代理对象,而不是原始对象。
总结:
代理的创建时机
初始化之后 (无循环依赖时)
实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存
依赖注入与初始化不应该被增强, 仍应被施加于原始对象
高级切面转换为低级切面 在findEligibleAdvisors()
方法执行时,会将遇到的Aspect
切面转换为advisor
的实现,这里介绍将高级切面转换为低级切面的过程。
编写示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public class A17_2 { 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" ); } public void afterReturning () { System.out.println("afterReturning" ); } public void afterThrowing () { System.out.println("afterThrowing" ); } 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 ()); 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); } } for (Advisor advisor : list) { System.out.println(advisor); } } }
@Before
前置通知会被转换为原始的 AspectJMethodBeforeAdvice
形式,该对象包含了如下信息:
通知代码从哪儿来
切点是什么
通知对象如何创建, 本例共用同一个Aspect
对象
除了AspectJMethodBeforeAdvice
,类似的通知还有:
AspectJAroundAdvice
(环绕通知)
AspectJAfterReturningAdvice
AspectJAfterThrowingAdvice
AspectJAfterAdvice
(环绕通知)
@Order注解 编写示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 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); context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class); context.refresh(); Object o1 = creator.wrapIfNecessary(new Target1 (), "target1" , "target1" ); ((Target1) o1).foo(); } static class Target1 { public void foo () { System.out.println("target1 foo" ); } } static class Target2 { public void bar () { System.out.println("target2 bar" ); } } @Aspect static class Aspect1 { @Before("execution(* foo())") public void before1 () { System.out.println("aspect1 before1..." ); } @After("execution(* foo())") public void before2 () { System.out.println("aspect1 after1..." ); } } @Configuration static class Config { @Bean public Advisor advisor3 (MethodInterceptor advice3) { AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut (); pointcut.setExpression("execution(* foo())" ); DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor (pointcut, advice3); return advisor; } @Bean public MethodInterceptor advice3 () { return invocation -> { System.out.println("advice3 before..." ); Object result = invocation.proceed(); System.out.println("advice3 after..." ); return result; }; } } }
运行启动类,查看控制台:
1 2 3 4 5 advice3 before... aspect1 before1... target1 foo aspect1 after1... advice3 after...
我们发现默认advisor
实现的代理先执行,@Aspect
注解实现的代理后执行,对于@Aspect
切面方式来讲,我们可以使用@Order
注解调整代理的优先级:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Aspect @Order(1) static class Aspect1 { @Before("execution(* foo())") public void before1 () { System.out.println("aspect1 before1..." ); } @After("execution(* foo())") public void before2 () { System.out.println("aspect1 after1..." ); } }
运行启动类,查看控制台:
1 2 3 4 5 aspect1 before1... advice3 before... target1 foo advice3 after... aspect1 after1...
对于advisor
切面方式,我们可以使用setOrder()
方法设置优先级:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Configuration static class Config { @Bean 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; }; } }
运行启动类,查看控制台:
1 2 3 4 5 advice3 before... aspect1 before1... target1 foo aspect1 after1... advice3 after...
缺点:
@Order
注解只能加在@Aspect 类上
类中所有方法的order
权值都相同
底层的通知实现 统一转换为环绕通知 其实无论ProxyFactory
基于哪种方式创建代理, 最后干活(调用advice
)的是一个MethodInvocation
对象
因为advisor
有多个, 且一个套一个调用, 因此需要一个调用链对象, 即MethodInvocation
MethodInvocation
要知道advice
有哪些, 还要知道目标, 调用次序如下
1 2 3 4 5 6 7 8 9 10 将 MethodInvocation 放入当前线程 |-> before1 ----------------------------------- 从当前线程获取 MethodInvocation | | | |-> before2 -------------------- | 从当前线程获取 MethodInvocation | | | | | | |-> target ------ 目标 advice2 advice1 | | | | | |-> after2 --------------------- | | | |-> after1 ------------------------------------
从上图看出, 环绕通知才适合作为 advice, 因此其他 before、afterReturning 都会被转换成环绕通知
统一转换为环绕通知, 体现的是设计模式中的适配器模式:
对外是为了方便使用要区分 before、afterReturning
对内统一都是环绕通知, 统一用 MethodInterceptor 表示
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 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 ()); 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); } Target target = new Target (); ProxyFactory proxyFactory = new ProxyFactory (); proxyFactory.setTarget(target); 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); } } }
运行启动类,查看控制台:
1 2 3 4 5 6 7 8 9 org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.before1()]; aspect name ''] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAfterReturningAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.afterReturning()]; aspect name ''] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.before2()]; aspect name ''] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name ''] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@52bf72b5 org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor@37afeb11 org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@515aebb0 org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name ''
我们发现AspectJMethodBeforeAdvice
已经被转换为MethodBeforeAdviceInterceptor
,AspectJAfterReturningAdvice
被转换为AfterReturningAdviceInterceptor
,AspectJAroundAdvice
本身就是环绕通知,不用被转换。
事实上只要实现MethodInterceptor
接口的都不用转换:
AspectJMethodBeforeAdvice
(前置通知):未实现MethodInterceptor
接口。
AspectJAroundAdvice
(环绕通知):实现了MethodInterceptor
接口。
AspectJAfterReturningAdvice
:未实现MethodInterceptor
接口。
AspectJAfterThrowingAdvice
:实现了MethodInterceptor
接口。
AspectJAfterAdvice
:实现了MethodInterceptor
接口。
适配器模式 对于通知解析,我们需要的是MethodInterceptor
接口,但解析后可能是另外的接口,因此需要将不符合MethodInterceptor
接口的类转换为实现MethodInterceptor
接口的类,这就需要使用到适配器模式。
统一转换为 MethodInterceptor
环绕通知, 这体现在方法名中的Interceptors
上
适配如下:
MethodBeforeAdviceAdapter
将@Before
AspectJMethodBeforeAdvice
适配为MethodBeforeAdviceInterceptor
AfterReturningAdviceAdapter
将 @AfterReturning
AspectJAfterReturningAdvice
适配为 AfterReturningAdviceInterceptor
我们可以查看MethodBeforeAdviceAdapter
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class MethodBeforeAdviceAdapter implements AdvisorAdapter , Serializable { MethodBeforeAdviceAdapter() { } public boolean supportsAdvice (Advice advice) { return advice instanceof MethodBeforeAdvice; } public MethodInterceptor getInterceptor (Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice(); return new MethodBeforeAdviceInterceptor (advice); } }
查看AfterReturningAdviceAdapter
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class AfterReturningAdviceAdapter implements AdvisorAdapter , Serializable { AfterReturningAdviceAdapter() { } public boolean supportsAdvice (Advice advice) { return advice instanceof AfterReturningAdvice; } public MethodInterceptor getInterceptor (Advisor advisor) { AfterReturningAdvice advice = (AfterReturningAdvice)advisor.getAdvice(); return new AfterReturningAdviceInterceptor (advice); } }
调用链的执行 通知统一转换为环绕通知之后,需要使用调用链来进行调用,调用链=所有的环绕通知+目标。
添加调用链并执行:
1 2 3 4 5 MethodInvocation methodInvocation = new ReflectiveMethodInvocation ( null , target, Target.class.getMethod("foo" ), new Object [0 ], Target.class, methodInterceptorList ); methodInvocation.proceed();
运行后会发现报错:
1 2 3 4 5 6 7 Exception in thread "main" java.lang.IllegalStateException: No MethodInvocation found: Check that an AOP invocation is in progress and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor! In addition, ExposeInvocationInterceptor and ExposeInvocationInterceptor.currentInvocation() must be invoked from the same thread. at org.springframework.aop.interceptor.ExposeInvocationInterceptor.currentInvocation(ExposeInvocationInterceptor.java:74) at org.springframework.aop.aspectj.AbstractAspectJAdvice.getJoinPointMatch(AbstractAspectJAdvice.java:658) at org.springframework.aop.aspectj.AspectJMethodBeforeAdvice.before(AspectJMethodBeforeAdvice.java:44) at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:57) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.A18.main(A18.java:162)
这是因为某些通知内部需要用到调用链对象,所以应该在最外层将调用链对象准备好,将 MethodInvocation 放入当前线程:
1 proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
完整示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 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 ()); 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); } Target target = new Target (); ProxyFactory proxyFactory = new ProxyFactory (); proxyFactory.setTarget(target); 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(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" ); MethodInvocation methodInvocation = new ReflectiveMethodInvocation ( null , target, Target.class.getMethod("foo" ), new Object [0 ], Target.class, methodInterceptorList ); methodInvocation.proceed(); } }
运行启动类,查看控制台:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.before1()]; aspect name '' ] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.before2()]; aspect name '' ] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name '' ] org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.aspectj.AspectJAfterReturningAdvice: advice method [public void org.springframework.aop.framework.A18$Aspect.afterReturning()]; aspect name '' ] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> org.springframework.aop.interceptor.ExposeInvocationInterceptor@1d2adfbe org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@36902638 org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@223d2c72 org.springframework.aop.aspectj.AspectJAroundAdvice: advice method [public java.lang.Object org.springframework.aop.framework.A18$Aspect.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable]; aspect name '' org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor@8f4ea7c >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> before1 before2 around...before target foo afterReturning around...after
成功执行了调用链。
模拟实现调用链 调用链实际上是使用的责任链模式,示例代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 public class A18_1 { static class Target { public void foo () { System.out.println("Target.foo()" ); } } static class Advice1 implements MethodInterceptor { 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 { 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; private Method method; private Object[] args; List<MethodInterceptor> methodInterceptorList; 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); } 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(); } }
运行启动类,查看控制台:
1 2 3 4 5 Advice1.before() Advice2.before() Target.foo() Advice2.after() Advice1.after()
动态通知调用 静态通知与动态通知对比:
静态通知调用,不带参数绑定,执行时不需要切点
动态通知调用,需要参数绑定,执行时还需要切点对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Aspect static class MyAspect { @Before("execution(* foo(..))") public void before1 () { System.out.println("before1" ); } @Before("execution(* foo(..)) && args(x)") public void before2 (int x) { System.out.printf("before2(%d)%n" , x); } }
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 public class A19 { @Aspect static class MyAspect { @Before("execution(* foo(..))") public void before1 () { System.out.println("before1" ); } @Before("execution(* foo(..)) && args(x)") public void before2 (int x) { System.out.printf("before2(%d)%n" , x); } } static class Target { public void foo (int x) { System.out.printf("target foo(%d)%n" , x); } } @Configuration static class MyConfig { @Bean AnnotationAwareAspectJAutoProxyCreator proxyCreator () { return new AnnotationAwareAspectJAutoProxyCreator (); } @Bean public MyAspect myAspect () { return new MyAspect (); } } public static void main (String[] args) throws Throwable { GenericApplicationContext context = new GenericApplicationContext (); context.registerBean(ConfigurationClassPostProcessor.class); context.registerBean(MyConfig.class); context.refresh(); AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class); List<Advisor> list = creator.findEligibleAdvisors(Target.class, "target" ); Target target = new Target (); ProxyFactory factory = new ProxyFactory (); factory.setTarget(target); factory.addAdvisors(list); Object proxy = factory.getProxy(); List<Object> interceptorList = factory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo" , int .class), Target.class); for (Object o : interceptorList) { showDetail(o); } System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>" ); ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation ( proxy, target, Target.class.getMethod("foo" , int .class), new Object []{100 }, Target.class, interceptorList ) {}; invocation.proceed(); } public static void showDetail (Object o) { try { Class<?> clazz = Class.forName("org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher" ); if (clazz.isInstance(o)) { Field methodMatcher = clazz.getDeclaredField("methodMatcher" ); methodMatcher.setAccessible(true ); Field methodInterceptor = clazz.getDeclaredField("interceptor" ); methodInterceptor.setAccessible(true ); System.out.println("环绕通知和切点:" + o); System.out.println("\t切点为:" + methodMatcher.get(o)); System.out.println("\t通知为:" + methodInterceptor.get(o)); } else { System.out.println("普通环绕通知:" + o); } } catch (Exception e) { e.printStackTrace(); } } }
运行启动类,查看控制台:
1 2 3 4 5 6 7 8 9 10 [INFO ] 16:25:32.123 [main] o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.aop.framework.autoproxy.A19$MyConfig' of type [org.springframework.aop.framework.autoproxy.A19$MyConfig$$EnhancerBySpringCGLIB$$4d8924fd] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 普通环绕通知:org.springframework.aop.interceptor.ExposeInvocationInterceptor@63fbfaeb 普通环绕通知:org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@2c07545f 环绕通知和切点:org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher@e57b96d 切点为:AspectJExpressionPointcut: (int x) execution(* foo(..)) && args(x) 通知为:org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor@34c01041 >>>>>>>>>>>>>>>>>>>>>>>>>> before1 before2(100) target foo(100)
进入InterceptorAndDynamicMethodMatcher
中,我们发现它没有实现MethodInterceptor
接口,但其成员变量却有:
1 2 3 4 final MethodInterceptor interceptor;final MethodMatcher methodMatcher;
我们在使用invocation
调用的时候,需要传入参数。
总结:
有参数绑定的通知调用时还需要切点,对参数进行匹配及绑定
复杂程度高, 性能比无参数绑定的通知调用低