• AOP 实现的几种方法 arthas工具分析


    9) AOP 实现之 ajc 编译器

    代码参考项目 demo6_advanced_aspectj_01

    收获💡

    1. 编译器也能修改 class 实现增强

    2. 编译器增强能突破代理仅能通过方法重写增强的限制:可以对构造方法、静态方法等实现增强

    项目地址:demo6_advanced_aspectj_01https://github.com/LJay997/demo6_advanced_aspectj_01

    查看IDEA 编译的class文件可看出ajc帮我们修改了源码实现了增强静态方法

    10) AOP 实现之 agent 类加载

    代码参考项目 demo6_advanced_aspectj_02

    收获💡

    1. 类加载时可以通过 agent 修改 class 实现增强

    demo6_advanced_aspectj_02https://github.com/LJay997/demo6_advanced_aspectj_02项目地址:git@github.com:LJay997/demo6_advanced_aspectj_02.git

     使用 Alibaba开源的Java诊断工具  Arthashttps://github.com/alibaba/arthas/blob/master/README_CN.md 反编译运行时的文件

            下载arthas-boot.jar,然后用java -jar的方式启动:

    1. curl -O https://arthas.aliyun.com/arthas-boot.jar
    2. 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 动态代理

    1. interface Foo {
    2. void foo();
    3. int bar();
    4. }
    1. class Target implements Foo {
    2. @Override
    3. public int bar() {
    4. return 0;
    5. }
    6. @Override
    7. public void foo() {
    8. System.out.println("target foo");
    9. }
    10. }
    1. public class JdkProxy {
    2. public static void main(String[] args) throws IOException {
    3. // method.invoke 需要传递 target
    4. Target target = new Target();
    5. ClassLoader loader = JdkProxy.class.getClassLoader();
    6. // Proxy.newProxyInstance ClassLoader [] Class[]
    7. // java.lang.reflect 生成的代理对象需要是接口实现的方法 代理与目标是同级关系
    8. Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (tmpProxy, method, args1) -> {
    9. System.out.println("before");
    10. // method.invoke 参数1 需要传递
    11. return method.invoke(target, args1);
    12. });
    13. // 执行代理方法
    14. proxy.foo();
    15. // 获取当前代理方法的类
    16. System.out.println(proxy.getClass());
    17. // 防止程序自己终止
    18. System.in.read();
    19. }
    20. }

    使用arthas工具查看 JdkProxy运行期间动态生成(ASM)生成的代理类的源码。

    1. # 运行 arthas
    2. java -jar .\arthas-boot.jar
    3. # 查看到程序的代号输入(回车确认)
    4. 4
    5. # jad 命令反编译
    6. jad $Proxy0

     arthas 获取的源码JdkProxy

    1. package a11;
    2. import a11.Foo;
    3. import java.lang.reflect.InvocationHandler;
    4. import java.lang.reflect.Method;
    5. import java.lang.reflect.Proxy;
    6. import java.lang.reflect.UndeclaredThrowableException;
    7. final class $Proxy0
    8. extends Proxy
    9. implements Foo {
    10. // 获取接口所有的方法
    11. private static Method m1;
    12. private static Method m2;
    13. private static Method m3;
    14. private static Method m4;
    15. private static Method m0;
    16. // 实现构造方法 Proxy
    17. public $Proxy0(InvocationHandler invocationHandler) {
    18. super(invocationHandler);
    19. }
    20. public final boolean equals(Object object) {
    21. try {
    22. return (Boolean)this.h.invoke(this, m1, new Object[]{object});
    23. }
    24. catch (Error | RuntimeException throwable) {
    25. throw throwable;
    26. }
    27. catch (Throwable throwable) {
    28. throw new UndeclaredThrowableException(throwable);
    29. }
    30. }
    31. public final String toString() {
    32. try {
    33. return (String)this.h.invoke(this, m2, null);
    34. }
    35. catch (Error | RuntimeException throwable) {
    36. throw throwable;
    37. }
    38. catch (Throwable throwable) {
    39. throw new UndeclaredThrowableException(throwable);
    40. }
    41. }
    42. public final int bar() {
    43. try {
    44. return (Integer)this.h.invoke(this, m3, null);
    45. }
    46. catch (Error | RuntimeException throwable) {
    47. throw throwable;
    48. }
    49. catch (Throwable throwable) {
    50. throw new UndeclaredThrowableException(throwable);
    51. }
    52. }
    53. public final void foo() {
    54. try {
    55. this.h.invoke(this, m4, null);
    56. return;
    57. }
    58. catch (Error | RuntimeException throwable) {
    59. throw throwable;
    60. }
    61. catch (Throwable throwable) {
    62. throw new UndeclaredThrowableException(throwable);
    63. }
    64. }
    65. public final int hashCode() {
    66. try {
    67. return (Integer)this.h.invoke(this, m0, null);
    68. }
    69. catch (Error | RuntimeException throwable) {
    70. throw throwable;
    71. }
    72. catch (Throwable throwable) {
    73. throw new UndeclaredThrowableException(throwable);
    74. }
    75. }
    76. static {
    77. try {
    78. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
    79. m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
    80. m3 = Class.forName("a11.Foo").getMethod("bar", new Class[0]);
    81. m4 = Class.forName("a11.Foo").getMethod("foo", new Class[0]);
    82. m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
    83. return;
    84. }
    85. catch (NoSuchMethodException noSuchMethodException) {
    86. throw new NoSuchMethodError(noSuchMethodException.getMessage());
    87. }
    88. catch (ClassNotFoundException classNotFoundException) {
    89. throw new NoClassDefFoundError(classNotFoundException.getMessage());
    90. }
    91. }
    92. }

    使用IDEA插件ASM加载字节码文件

     main 方法中补充

    1. byte[] dump = $Proxy0Dump.dump();
    2. ClassLoader classLoader = new ClassLoader() {
    3. @Override
    4. protected Class findClass(String name) throws ClassNotFoundException {
    5. // 将字节数组转换为Class 类的实例
    6. return super.defineClass(name, dump, 0, dump.length);
    7. }
    8. };
    9. Class proxy0 = classLoader.loadClass("$Proxy0");
    10. Constructor constructor = proxy0.getConstructor(InvocationHandler.class);
    11. Foo proxy = (Foo)constructor.newInstance(new InvocationHandler() {
    12. @Override
    13. public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
    14. return null;
    15. }
    16. });
    17. proxy.foo();
    18. // .....JDK 代理方法
    19. Target target = new Target();
    20. // ......

    JDK 代理的优化

    在反射调用第17次时候 代理类变化了 

    16:jdk.internal.reflect.NativeMethodAccessorImpl@cb5822  ->
    17:jdk.internal.reflect.GeneratedMethodAccessor2@26653222

    1. public class TestMethodInvoke {
    2. public static void main(String[] args) throws Exception {
    3. Method foo = TestMethodInvoke.class.getMethod("foo", int.class);
    4. for (int i = 1; i <= 17; i++) {
    5. show(i, foo);
    6. foo.invoke(null, i);
    7. }
    8. System.in.read();
    9. }
    10. // 方法反射调用时, 底层 MethodAccessor 的实现类
    11. private static void show(int i, Method foo) throws Exception {
    12. Method getMethodAccessor = Method.class.getDeclaredMethod("getMethodAccessor");
    13. getMethodAccessor.setAccessible(true);
    14. Object invoke = getMethodAccessor.invoke(foo);
    15. if (invoke == null) {
    16. System.out.println(i + ":" + null);
    17. return;
    18. }
    19. Field delegate = Class.forName("jdk.internal.reflect.DelegatingMethodAccessorImpl").getDeclaredField("delegate");
    20. delegate.setAccessible(true);
    21. System.out.println(i + ":" + delegate.get(invoke));
    22. }
    23. public static void foo(int i) {
    24. System.out.println(i + ":" + "foo");
    25. }
    26. }

    收获💡

    • jdk 动态代理要求目标必须实现接口,生成的代理类实现相同接口,因此代理与目标之间是平级兄弟关系

    演示2 - cglib 代理

    1. import org.springframework.cglib.proxy.MethodInterceptor;
    2. import org.springframework.cglib.proxy.MethodProxy;
    3. import java.io.IOException;
    4. import java.lang.reflect.Method;
    5. public class CglibProxy {
    6. static class Target {
    7. void foo() {
    8. System.out.println("target foo");
    9. }
    10. }
    11. public static void main(String[] args) throws IOException {
    12. Target target = new Target();
    13. // public static Object create(Class type, Callback callback) 第二个参数 使用 MethodInterceptor extends Callback
    14. // cglib 生产的类型为目标类型的 子类型(方法重写) 目标方法&目标类不能是final类型的
    15. Target proxy = (Target)Enhancer.create(Target.class, new MethodInterceptor() {
    16. @Override
    17. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    18. System.out.println("before");
    19. // Object invoke = method.invoke(target, objects); // 用方法反射调用目标
    20. Object invoke = methodProxy.invoke(target, objects); // 没有用反射 - 推荐
    21. // Object invoke = methodProxy.invokeSuper(o, objects); // 没有用反射 需要代理
    22. System.out.println("after");
    23. return invoke;
    24. }
    25. });
    26. proxy.foo();
    27. System.out.println(proxy.getClass());
    28. System.in.read();
    29. }
    30. }

    arthas 获取运行时class

    1. package a11;
    2. import a11.CglibProxy;
    3. import java.lang.reflect.Method;
    4. import org.springframework.cglib.core.ReflectUtils;
    5. import org.springframework.cglib.core.Signature;
    6. import org.springframework.cglib.proxy.Callback;
    7. import org.springframework.cglib.proxy.Factory;
    8. import org.springframework.cglib.proxy.MethodInterceptor;
    9. import org.springframework.cglib.proxy.MethodProxy;
    10. public class CglibProxy$Target$$EnhancerByCGLIB$$f6222c24
    11. extends CglibProxy.Target
    12. implements Factory {
    13. // Method MethodProxy 重点
    14. private boolean CGLIB$BOUND;
    15. public static Object CGLIB$FACTORY_DATA;
    16. private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    17. private static final Callback[] CGLIB$STATIC_CALLBACKS;
    18. private MethodInterceptor CGLIB$CALLBACK_0;
    19. private static Object CGLIB$CALLBACK_FILTER;
    20. private static final Method CGLIB$foo$0$Method;
    21. private static final MethodProxy CGLIB$foo$0$Proxy;
    22. private static final Object[] CGLIB$emptyArgs;
    23. private static final Method CGLIB$equals$1$Method;
    24. private static final MethodProxy CGLIB$equals$1$Proxy;
    25. private static final Method CGLIB$toString$2$Method;
    26. private static final MethodProxy CGLIB$toString$2$Proxy;
    27. private static final Method CGLIB$hashCode$3$Method;
    28. private static final MethodProxy CGLIB$hashCode$3$Proxy;
    29. private static final Method CGLIB$clone$4$Method;
    30. private static final MethodProxy CGLIB$clone$4$Proxy;
    31. static void CGLIB$STATICHOOK1() {
    32. CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    33. CGLIB$emptyArgs = new Object[0];
    34. Class clazz = Class.forName("a11.CglibProxy$Target$$EnhancerByCGLIB$$f6222c24");
    35. Class clazz2 = Class.forName("java.lang.Object");
    36. Method[] methodArray = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, clazz2.getDeclaredMethods());
    37. CGLIB$equals$1$Method = methodArray[0];
    38. CGLIB$equals$1$Proxy = MethodProxy.create(clazz2, clazz, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
    39. CGLIB$toString$2$Method = methodArray[1];
    40. CGLIB$toString$2$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
    41. CGLIB$hashCode$3$Method = methodArray[2];
    42. CGLIB$hashCode$3$Proxy = MethodProxy.create(clazz2, clazz, "()I", "hashCode", "CGLIB$hashCode$3");
    43. CGLIB$clone$4$Method = methodArray[3];
    44. CGLIB$clone$4$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
    45. clazz2 = Class.forName("a11.CglibProxy$Target");
    46. CGLIB$foo$0$Method = ReflectUtils.findMethods(new String[]{"foo", "()V"}, clazz2.getDeclaredMethods())[0];
    47. CGLIB$foo$0$Proxy = MethodProxy.create(clazz2, clazz, "()V", "foo", "CGLIB$foo$0");
    48. }
    49. // 带原始功能的方法
    50. final void CGLIB$foo$0() {
    51. super.foo();
    52. }
    53. // 带增强功能的方法
    54. @Override
    55. final void foo() {
    56. MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
    57. if (methodInterceptor == null) {
    58. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
    59. methodInterceptor = this.CGLIB$CALLBACK_0;
    60. }
    61. if (methodInterceptor != null) {
    62. Object object = methodInterceptor.intercept(this, CGLIB$foo$0$Method, CGLIB$emptyArgs, CGLIB$foo$0$Proxy);
    63. return;
    64. }
    65. super.foo();
    66. }
    67. final boolean CGLIB$equals$1(Object object) {
    68. return super.equals(object);
    69. }
    70. public final boolean equals(Object object) {
    71. MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
    72. if (methodInterceptor == null) {
    73. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
    74. methodInterceptor = this.CGLIB$CALLBACK_0;
    75. }
    76. if (methodInterceptor != null) {
    77. Object object2 = methodInterceptor.intercept(this, CGLIB$equals$1$Method, new Object[]{object}, CGLIB$equals$1$Proxy);
    78. return object2 == null ? false : (Boolean)object2;
    79. }
    80. return super.equals(object);
    81. }
    82. final String CGLIB$toString$2() {
    83. return super.toString();
    84. }
    85. public final String toString() {
    86. MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
    87. if (methodInterceptor == null) {
    88. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
    89. methodInterceptor = this.CGLIB$CALLBACK_0;
    90. }
    91. if (methodInterceptor != null) {
    92. return (String)methodInterceptor.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy);
    93. }
    94. return super.toString();
    95. }
    96. final int CGLIB$hashCode$3() {
    97. return super.hashCode();
    98. }
    99. public final int hashCode() {
    100. MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
    101. if (methodInterceptor == null) {
    102. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
    103. methodInterceptor = this.CGLIB$CALLBACK_0;
    104. }
    105. if (methodInterceptor != null) {
    106. Object object = methodInterceptor.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
    107. return object == null ? 0 : ((Number)object).intValue();
    108. }
    109. return super.hashCode();
    110. }
    111. final Object CGLIB$clone$4() throws CloneNotSupportedException {
    112. return super.clone();
    113. }
    114. protected final Object clone() throws CloneNotSupportedException {
    115. MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
    116. if (methodInterceptor == null) {
    117. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
    118. methodInterceptor = this.CGLIB$CALLBACK_0;
    119. }
    120. if (methodInterceptor != null) {
    121. return methodInterceptor.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy);
    122. }
    123. return super.clone();
    124. }
    125. public static MethodProxy CGLIB$findMethodProxy(Signature signature) {
    126. String string = ((Object)signature).toString();
    127. switch (string.hashCode()) {
    128. case -1268936465: {
    129. if (!string.equals("foo()V")) break;
    130. return CGLIB$foo$0$Proxy;
    131. }
    132. case -508378822: {
    133. if (!string.equals("clone()Ljava/lang/Object;")) break;
    134. return CGLIB$clone$4$Proxy;
    135. }
    136. case 1826985398: {
    137. if (!string.equals("equals(Ljava/lang/Object;)Z")) break;
    138. return CGLIB$equals$1$Proxy;
    139. }
    140. case 1913648695: {
    141. if (!string.equals("toString()Ljava/lang/String;")) break;
    142. return CGLIB$toString$2$Proxy;
    143. }
    144. case 1984935277: {
    145. if (!string.equals("hashCode()I")) break;
    146. return CGLIB$hashCode$3$Proxy;
    147. }
    148. }
    149. return null;
    150. }
    151. public CglibProxy$Target$$EnhancerByCGLIB$$f6222c24() {
    152. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
    153. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(cglibProxy$Target$$EnhancerByCGLIB$$f6222c24);
    154. }
    155. public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] callbackArray) {
    156. CGLIB$THREAD_CALLBACKS.set(callbackArray);
    157. }
    158. public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callbackArray) {
    159. CGLIB$STATIC_CALLBACKS = callbackArray;
    160. }
    161. private static final void CGLIB$BIND_CALLBACKS(Object object) {
    162. block2: {
    163. Object object2;
    164. block3: {
    165. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = (CglibProxy$Target$$EnhancerByCGLIB$$f6222c24)object;
    166. if (cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BOUND) break block2;
    167. cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BOUND = true;
    168. object2 = CGLIB$THREAD_CALLBACKS.get();
    169. if (object2 != null) break block3;
    170. object2 = CGLIB$STATIC_CALLBACKS;
    171. if (CGLIB$STATIC_CALLBACKS == null) break block2;
    172. }
    173. cglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])object2)[0];
    174. }
    175. }
    176. @Override
    177. public Object newInstance(Callback[] callbackArray) {
    178. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
    179. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
    180. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
    181. return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
    182. }
    183. @Override
    184. public Object newInstance(Callback callback) {
    185. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(new Callback[]{callback});
    186. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
    187. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
    188. return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
    189. }
    190. @Override
    191. public Object newInstance(Class[] classArray, Object[] objectArray, Callback[] callbackArray) {
    192. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
    193. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
    194. Class[] classArray2 = classArray;
    195. switch (classArray.length) {
    196. case 0: {
    197. cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = new CglibProxy$Target$$EnhancerByCGLIB$$f6222c24();
    198. break;
    199. }
    200. default: {
    201. throw new IllegalArgumentException("Constructor not found");
    202. }
    203. }
    204. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$SET_THREAD_CALLBACKS(null);
    205. return cglibProxy$Target$$EnhancerByCGLIB$$f6222c24;
    206. }
    207. @Override
    208. public Callback getCallback(int n) {
    209. MethodInterceptor methodInterceptor;
    210. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
    211. switch (n) {
    212. case 0: {
    213. methodInterceptor = this.CGLIB$CALLBACK_0;
    214. break;
    215. }
    216. default: {
    217. methodInterceptor = null;
    218. }
    219. }
    220. return methodInterceptor;
    221. }
    222. @Override
    223. public void setCallback(int n, Callback callback) {
    224. switch (n) {
    225. case 0: {
    226. this.CGLIB$CALLBACK_0 = (MethodInterceptor)callback;
    227. break;
    228. }
    229. }
    230. }
    231. @Override
    232. public Callback[] getCallbacks() {
    233. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$BIND_CALLBACKS(this);
    234. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
    235. return new Callback[]{this.CGLIB$CALLBACK_0};
    236. }
    237. @Override
    238. public void setCallbacks(Callback[] callbackArray) {
    239. Callback[] callbackArray2 = callbackArray;
    240. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24 cglibProxy$Target$$EnhancerByCGLIB$$f6222c24 = this;
    241. this.CGLIB$CALLBACK_0 = (MethodInterceptor)callbackArray[0];
    242. }
    243. static {
    244. CglibProxy$Target$$EnhancerByCGLIB$$f6222c24.CGLIB$STATICHOOK1();
    245. }
    246. }

    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

    1. interface I1 {
    2. void foo();
    3. void bar();
    4. }
    5. static class Target1 implements I1 {
    6. public void foo() {
    7. System.out.println("target1 foo");
    8. }
    9. public void bar() {
    10. System.out.println("target1 bar");
    11. }
    12. }
    13. static class Target2 {
    14. public void foo() {
    15. System.out.println("target2 foo");
    16. }
    17. public void bar() {
    18. System.out.println("target2 bar");
    19. }
    20. }
    1. import org.aopalliance.intercept.MethodInterceptor;
    2. import org.springframework.aop.aspectj.AspectJExpressionPointcut;
    3. import org.springframework.aop.framework.ProxyFactory;
    4. import org.springframework.aop.support.DefaultPointcutAdvisor;
    5. public class Demo {
    6. public static void main(String[] args) {
    7. // 1.添加切入点 pointcut
    8. AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    9. pointcut.setExpression("execution(* foo())");
    10. // 2.添加通知Advice org.aopalliance.intercept.MethodInterceptor
    11. MethodInterceptor advice = invocation -> {
    12. System.out.println("before");
    13. Object proceed = invocation.proceed(); // 调用目标
    14. System.out.println("after");
    15. return proceed;
    16. };
    17. // 3.添加切面 Advisor !! 重要 反向查找就是找一下 advisor 下有 pointcut实现类 的类就可以了!!
    18. // DefaultPointcutAdvisor 与 AspectJExpressionPointcut 同属于 AbstractGenericPointcutAdvisor
    19. DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
    20. // 4. 创建代理
    21. A15.Target1 target = new A15.Target1();
    22. ProxyFactory proxyFactory = new ProxyFactory();
    23. proxyFactory.setInterfaces(target.getClass().getInterfaces()); // 如果实现了接口必须setInterfaces ProxyFactory不会自动检测
    24. // proxyFactory.setTargetClass(target.getClass()); // proxyFactory.getProxy使用的 CGLIB 实现 返回类型需要改为 I1 的子类
    25. proxyFactory.setTarget(target);
    26. proxyFactory.addAdvisor(advisor);
    27. A15.I1 proxy = (A15.I1)proxyFactory.getProxy();
    28. proxy.foo();
    29. System.out.println(proxy.getClass());
    30. // spring 代理的实现由两种 JDKProxy 与 CGLIB
    31. // 1.未setInterfaces 未 setTargetClass CGLIB
    32. // 2.setInterfaces 未 setTargetClass JDKProxy
    33. // 3. setTargetClass CGLIB
    34. }
    35. }

    proxyFactory.setInterfaces(target.getClass().getInterfaces()); proxyFactory.setTargetClass(target.getClass());

    切点匹配

    PointCut 的重要属性 org.springframework.aop.MethodMatcher 检查目标方法是否有资格获得advice

            对使用了注解标注(对整个类型层次结构执行完整搜索,包括超类和实现的接口)的方法进行增强

    1. StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut() {
    2. // 执行静态检查给定方法是否匹配
    3. @Override
    4. public boolean matches(Method method, Class targetClass) {
    5. // MergedAnnotations可以从任何 Java AnnotatedElement获得。
    6. // 可以使用不同的搜索策略来定位包含要聚合的注释的相关源元素。
    7. // 例如, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY将搜索超类和实现的接口。
    8. // 检查方法上是否加了 Transactional 注解
    9. MergedAnnotations annotations = MergedAnnotations.from(method);
    10. if (annotations.isPresent(Transactional.class)) {
    11. return true;
    12. }
    13. //
    14. // 查看类上是否加了 Transactional 注解
    15. annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
    16. if (annotations.isPresent(Transactional.class)) {
    17. return true;
    18. }
    19. return false;
    20. }
    21. };
    22. System.out.println(pt3.matches(T1.class.getMethod("foo"), T1.class));

    17) 从 @Aspect 到 Advisor

    代理创建器

    代码参考

    org.springframework.aop.framework.autoproxy

    1. package org.springframework.aop.framework.autoproxy;
    2. import org.aopalliance.intercept.MethodInterceptor;
    3. import org.aopalliance.intercept.MethodInvocation;
    4. import org.aspectj.lang.JoinPoint;
    5. import org.aspectj.lang.annotation.AfterReturning;
    6. import org.aspectj.lang.annotation.Aspect;
    7. import org.aspectj.lang.annotation.Before;
    8. import org.springframework.aop.Advisor;
    9. import org.springframework.aop.aspectj.AspectJExpressionPointcut;
    10. import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
    11. import org.springframework.aop.support.DefaultPointcutAdvisor;
    12. import org.springframework.context.annotation.Bean;
    13. import org.springframework.context.annotation.Configuration;
    14. import org.springframework.context.annotation.ConfigurationClassPostProcessor;
    15. import org.springframework.context.support.GenericApplicationContext;
    16. import org.springframework.core.annotation.Order;
    17. import org.springframework.lang.NonNull;
    18. import java.util.List;
    19. public class A17 {
    20. public static void main(String[] args) {
    21. GenericApplicationContext context = new GenericApplicationContext();
    22. context.registerBean("aspect1", Aspect1.class);
    23. context.registerBean("config", Config.class);
    24. context.registerBean(ConfigurationClassPostProcessor.class);
    25. // 属于 BeanPostProcessor 初始化回调前(通过标记接口等填充 bean) 初始化回调后(而使用代理包装 bean)
    26. context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
    27. // BeanPostProcessor
    28. // 创建 -> (*) 依赖注入 -> 初始化 (*)
    29. context.refresh();
    30. // for (String name : context.getBeanDefinitionNames()) {
    31. // System.out.println(name);
    32. // }
    33. /*
    34. 第一个重要方法 findEligibleAdvisors 找到有【资格】的 Advisors
    35. a. 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如下例中的 advisor3
    36. b. 有【资格】的 Advisor 另一部分是高级的, 由本章的主角解析 @Aspect 后获得
    37. */
    38. AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
    39. List advisors = creator.findEligibleAdvisors(Target2.class, "target2");
    40. /*for (Advisor advisor : advisors) {
    41. System.out.println(advisor);
    42. }*/
    43. /*
    44. 第二个重要方法 wrapIfNecessary
    45. a. 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
    46. */
    47. Object o1 = creator.wrapIfNecessary(new Target1(), "target1", "target1");
    48. System.out.println(o1.getClass());
    49. Object o2 = creator.wrapIfNecessary(new Target2(), "target2", "target2");
    50. System.out.println(o2.getClass());
    51. ((Target1) o1).foo(new Target2("ss"));
    52. /*
    53. 学到了什么
    54. a. 自动代理后处理器 AnnotationAwareAspectJAutoProxyCreator 会帮我们创建代理
    55. b. 通常代理创建的活在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行
    56. c. 高级的 @Aspect 切面会转换为低级的 Advisor 切面, 理解原理, 大道至简
    57. */
    58. }
    59. static class Target1 {
    60. public void foo(Target2 ss) {
    61. System.out.println("target1 foo");
    62. }
    63. }
    64. static class Target2 {
    65. public Target2() {
    66. }
    67. public Target2(String ss) {
    68. this.ss = ss;
    69. }
    70. @NonNull
    71. private String ss;
    72. public String getSs() {
    73. return ss;
    74. }
    75. public void setSs(String ss) {
    76. this.ss = ss;
    77. }
    78. public void bar() {
    79. System.out.println("target2 bar");
    80. }
    81. }
    82. @Aspect // 高级切面类
    83. @Order(2)
    84. static class Aspect1 {
    85. @AfterReturning("execution(* foo(*))")
    86. public void before1(JoinPoint joinPoint) {
    87. System.out.println("aspect1 before1..." + (MethodInvocation)joinPoint);
    88. }
    89. @Before("execution(* foo())")
    90. public void before2() {
    91. System.out.println("aspect1 before2...");
    92. }
    93. }
    94. @Configuration
    95. static class Config {
    96. @Bean // 低级切面
    97. // @Order(1) p配置在此地方不生效
    98. public Advisor advisor3(MethodInterceptor advice3) {
    99. AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    100. pointcut.setExpression("execution(* foo())");
    101. DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice3);
    102. advisor.setOrder(1);
    103. return advisor;
    104. }
    105. @Bean
    106. public MethodInterceptor advice3() {
    107. return invocation -> {
    108. System.out.println("advice3 before...");
    109. Object result = invocation.proceed();
    110. System.out.println("advice3 after...");
    111. return result;
    112. };
    113. }
    114. }
    115. }

    收获💡

    1. AnnotationAwareAspectJAutoProxyCreator 的作用

      • 将高级 @Aspect 切面统一为低级 Advisor 切面

      • 在合适的时机创建代理

    2. findEligibleAdvisors 找到有【资格】的 Advisors

      • 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如本例 A17 中的 advisor3

      • 有【资格】的 Advisor 另一部分是高级的, 由解析 @Aspect 后获得

    3. wrapIfNecessary

      • 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理

      • 它的调用时机通常在原始对象初始化后执行, 但碰到循环依赖会提前至依赖注入之前执行

    演示2 - 代理创建时机

    代码参考

    org.springframework.aop.framework.autoproxy.A17_1

    1. static class Bean1 {
    2. public void foo() {
    3. }
    4. public Bean1() {
    5. System.out.println("Bean1()");
    6. }
    7. // 取消循环依赖就将该方法注释掉即可
    8. @Autowired public void setBean2(Bean2 bean2) {
    9. System.out.println("Bean1 setBean2(bean2) class is: " + bean2.getClass());
    10. }
    11. @PostConstruct public void init() {
    12. System.out.println("Bean1 init()");
    13. }
    14. }
    15. static class Bean2 {
    16. public Bean2() {
    17. System.out.println("Bean2()");
    18. }
    19. @Autowired public void setBean1(Bean1 bean1) {
    20. System.out.println("Bean2 setBean1(bean1) class is: " + bean1.getClass());
    21. }
    22. @PostConstruct public void init() {
    23. System.out.println("Bean2 init()");
    24. }
    25. }

     // 循环依赖演示

    注意 “Creating implicit proxy for bean 'bean1'”意思是增强了.

     // 无循环依赖

    Bean2 setBean1依赖注入Bean1 代理($Bean1)增强后($$EnhancerBySpringCGLIB)的对象

     // 工厂方法配置

    1. @Configuration
    2. static class Config {
    3. @Bean // 解析 @Aspect、产生代理
    4. public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
    5. return new AnnotationAwareAspectJAutoProxyCreator();
    6. }
    7. @Bean // 解析 @Autowired
    8. public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
    9. return new AutowiredAnnotationBeanPostProcessor();
    10. }
    11. @Bean // 解析 @PostConstruct
    12. public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
    13. return new CommonAnnotationBeanPostProcessor();
    14. }
    15. @Bean
    16. public Advisor advisor(MethodInterceptor advice) {
    17. AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    18. pointcut.setExpression("execution(* foo())");
    19. return new DefaultPointcutAdvisor(pointcut, advice);
    20. }
    21. @Bean
    22. public MethodInterceptor advice() {
    23. return (MethodInvocation invocation) -> {
    24. System.out.println("before...");
    25. return invocation.proceed();
    26. };
    27. }
    28. @Bean
    29. public Bean1 bean1() {
    30. return new Bean1();
    31. }
    32. @Bean
    33. public Bean2 bean2() {
    34. return new Bean2();
    35. }
    36. }

    // 主方法调用

    1. public static void main(String[] args) {
    2. GenericApplicationContext context = new GenericApplicationContext();
    3. context.registerBean(ConfigurationClassPostProcessor.class);
    4. context.registerBean(Config.class);
    5. context.refresh();
    6. context.close();
    7. // 创建 -> (*) 依赖注入 -> 初始化 (*)
    8. /*
    9. 学到了什么
    10. a. 代理的创建时机
    11. 1. 初始化之后 (无循环依赖时)
    12. 2. 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存
    13. b. 依赖注入与初始化不应该被增强, 仍应被施加于原始对象
    14. */
    15. }

    收获💡??

    创建 -> (1.2) 依赖注入 -> 初始化 (1.1)

    1. 代理的创建时机

      • 无循环依赖时:初始化之后 

      • 有循环依赖时:实例创建后, 依赖注入前 , 并暂存于二级缓存

    2. 依赖注入与初始化不应该被增强, 仍 应被施加于原始对象

    @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 + 目标)
    1. import org.aopalliance.intercept.MethodInvocation;
    2. import org.aspectj.lang.ProceedingJoinPoint;
    3. import org.aspectj.lang.annotation.AfterReturning;
    4. import org.aspectj.lang.annotation.AfterThrowing;
    5. import org.aspectj.lang.annotation.Around;
    6. import org.aspectj.lang.annotation.Before;
    7. import org.springframework.aop.Advisor;
    8. import org.springframework.aop.aspectj.*;
    9. import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
    10. import org.springframework.aop.support.DefaultPointcutAdvisor;
    11. import java.lang.reflect.Method;
    12. import java.util.ArrayList;
    13. import java.util.List;
    14. public class A18 {
    15. static class Aspect {
    16. @Before("execution(* foo())")
    17. public void before1() {
    18. System.out.println("before1");
    19. }
    20. @Before("execution(* foo())")
    21. public void before2() {
    22. System.out.println("before2");
    23. }
    24. public void after() {
    25. System.out.println("after");
    26. }
    27. @AfterReturning("execution(* foo())")
    28. public void afterReturning() {
    29. System.out.println("afterReturning");
    30. }
    31. @AfterThrowing("execution(* foo())")
    32. public void afterThrowing(Exception e) {
    33. System.out.println("afterThrowing " + e.getMessage());
    34. }
    35. @Around("execution(* foo())")
    36. public Object around(ProceedingJoinPoint pjp) throws Throwable {
    37. try {
    38. System.out.println("around...before");
    39. return pjp.proceed();
    40. } finally {
    41. System.out.println("around...after");
    42. }
    43. }
    44. }
    45. static class Target {
    46. public void foo() {
    47. System.out.println("target foo");
    48. }
    49. }
    50. @SuppressWarnings("all")
    51. public static void main(String[] args) throws Throwable {
    52. AspectInstanceFactory factory = new SingletonAspectInstanceFactory(new Aspect());
    53. // 1. 高级切面转低级切面类
    54. List list = new ArrayList<>();
    55. for (Method method : Aspect.class.getDeclaredMethods()) {
    56. if (method.isAnnotationPresent(Before.class)) {
    57. // 解析切点
    58. String expression = method.getAnnotation(Before.class).value();
    59. AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    60. pointcut.setExpression(expression);
    61. // 通知类
    62. AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pointcut, factory);
    63. // 切面
    64. Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
    65. list.add(advisor);
    66. } else if (method.isAnnotationPresent(AfterReturning.class)) {
    67. // 解析切点
    68. String expression = method.getAnnotation(AfterReturning.class).value();
    69. AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    70. pointcut.setExpression(expression);
    71. // 通知类
    72. AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(method, pointcut, factory);
    73. // 切面
    74. Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
    75. list.add(advisor);
    76. } else if (method.isAnnotationPresent(Around.class)) {
    77. // 解析切点
    78. String expression = method.getAnnotation(Around.class).value();
    79. AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    80. pointcut.setExpression(expression);
    81. // 通知类
    82. AspectJAroundAdvice advice = new AspectJAroundAdvice(method, pointcut, factory);
    83. // 切面
    84. Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
    85. list.add(advisor);
    86. }
    87. }
    88. for (Advisor advisor : list) {
    89. // 还要为低级的切面进行排序
    90. System.out.println(advisor);
    91. }
    92. /*
    93. @Before 前置通知会被转换为下面原始的 AspectJMethodBeforeAdvice 形式, 该对象包含了如下信息
    94. a. 通知代码从哪儿来
    95. b. 切点是什么
    96. c. 通知对象如何创建, 本例共用同一个 Aspect 对象
    97. 类似的通知还有
    98. 1. AspectJAroundAdvice (环绕通知)
    99. 2. AspectJAfterReturningAdvice
    100. 3. AspectJAfterThrowingAdvice (环绕通知)
    101. 4. AspectJAfterAdvice (环绕通知)
    102. */
    103. // 2. 通知统一转换为环绕通知 MethodInterceptor
    104. /*
    105. 其实无论 ProxyFactory 基于哪种方式创建代理, 最后干活(调用 advice)的是一个 MethodInvocation 对象
    106. a. 因为 advisor 有多个, 且一个套一个调用, 因此需要一个调用链对象, 即 MethodInvocation
    107. b. MethodInvocation 要知道 advice 有哪些, 还要知道目标, 调用次序如下
    108. !.将 MethodInvocation 放入当前线程
    109. |-> before1 ----------------------------------- 从当前线程获取 MethodInvocation
    110. | |
    111. | |-> before2 -------------------- | 从当前线程获取 MethodInvocation
    112. | | | |
    113. | | |-> target ------ 目标 advice2 advice1
    114. | | | |
    115. | |-> after2 --------------------- |
    116. | |
    117. |-> after1 ------------------------------------
    118. c. 从上图看出, 环绕通知才适合作为 advice, 因此其他 before、afterReturning 都会被转换成环绕通知
    119. d. 统一转换为环绕通知, 体现的是设计模式中的适配器模式
    120. - 对外是为了方便使用要区分 before、afterReturning
    121. - 对内统一都是环绕通知, 统一用 MethodInterceptor 表示
    122. 此步获取所有执行时需要的 advice (静态)
    123. a. 即统一转换为 MethodInterceptor 环绕通知, 这体现在方法名中的 Interceptors 上
    124. b. 适配如下
    125. - MethodBeforeAdviceAdapter 将 @Before AspectJMethodBeforeAdvice 适配为 MethodBeforeAdviceInterceptor
    126. - AfterReturningAdviceAdapter 将 @AfterReturning AspectJAfterReturningAdvice 适配为 AfterReturningAdviceInterceptor
    127. */
    128. Target target = new Target();
    129. ProxyFactory proxyFactory = new ProxyFactory();
    130. proxyFactory.setTarget(target);
    131. // !.准备把 MethodInvocation 放入当前线程,需要放在环绕通知的最外层,用于暴露 MethodInvocation 的一个工具类
    132. // 是单例的 使用的私有构造
    133. proxyFactory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
    134. proxyFactory.addAdvisors(list);
    135. System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
    136. List methodInterceptorList = proxyFactory.getInterceptorsAndDynamicInterceptionAdvice(Target.class.getMethod("foo"), Target.class);
    137. for (Object o : methodInterceptorList) {
    138. System.out.println(o);
    139. }
    140. System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
    141. // 3. 创建并执行调用链 (环绕通知s + 目标)
    142. MethodInvocation methodInvocation = new ReflectiveMethodInvocation(
    143. null, target, Target.class.getMethod("foo"), new Object[0], Target.class, methodInterceptorList
    144. );
    145. methodInvocation.proceed();
    146. /*
    147. 学到了什么
    148. a. 无参数绑定的通知如何被调用
    149. b. MethodInvocation 编程技巧: 拦截器、过滤器等等实现都与此类似
    150. c. 适配器模式在 Spring 中的体现
    151. */
    152. }
    153. }
    154. 代理对象调用流程如下(以 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. /*
      2. 模拟调用链过程, 是一个简单的递归过程
      3. 1. proceed() 方法调用链中下一个环绕通知
      4. 2. 每个环绕通知内部继续调用 proceed()
      5. 3. 调用到没有更多通知了, 就调用目标方法
      6. */
      7. public class A18_1 {
      8. static class Target {
      9. public void foo() {
      10. System.out.println("Target.foo()");
      11. }
      12. }
      13. static class Advice1 implements MethodInterceptor {
      14. @Override
      15. public Object invoke(MethodInvocation invocation) throws Throwable {
      16. System.out.println("Advice1.before()");
      17. Object result = invocation.proceed();// 调用下一个通知或目标
      18. System.out.println("Advice1.after()");
      19. return result;
      20. }
      21. }
      22. static class Advice2 implements MethodInterceptor {
      23. @Override
      24. public Object invoke(MethodInvocation invocation) throws Throwable {
      25. System.out.println("Advice2.before()");
      26. Object result = invocation.proceed();// 调用下一个通知或目标
      27. System.out.println("Advice2.after()");
      28. return result;
      29. }
      30. }
      31. static class MyInvocation implements MethodInvocation {
      32. private Object target; // 1
      33. private Method method;
      34. private Object[] args;
      35. List methodInterceptorList; // 2
      36. private int count = 1; // 调用次数
      37. public MyInvocation(Object target, Method method, Object[] args, List methodInterceptorList) {
      38. this.target = target;
      39. this.method = method;
      40. this.args = args;
      41. this.methodInterceptorList = methodInterceptorList;
      42. }
      43. @Override
      44. public Method getMethod() {
      45. return method;
      46. }
      47. @Override
      48. public Object[] getArguments() {
      49. return args;
      50. }
      51. @Override
      52. public Object proceed() throws Throwable { // 调用每一个环绕通知, 调用目标
      53. if (count > methodInterceptorList.size()) {
      54. // 调用目标, 返回并结束递归
      55. return method.invoke(target, args);
      56. }
      57. // 逐一调用通知, count + 1
      58. MethodInterceptor methodInterceptor = methodInterceptorList.get(count++ - 1);
      59. return methodInterceptor.invoke(this);
      60. }
      61. @Override
      62. public Object getThis() {
      63. return target;
      64. }
      65. @Override
      66. public AccessibleObject getStaticPart() {
      67. return method;
      68. }
      69. }
      70. public static void main(String[] args) throws Throwable {
      71. Target target = new Target();
      72. List list = List.of(
      73. new Advice1(),
      74. new Advice2()
      75. );
      76. MyInvocation invocation = new MyInvocation(target, Target.class.getMethod("foo"), new Object[0], list);
      77. invocation.proceed();
      78. }
      79. }

      ​​​​​​​


      aspectj.lang.annotation

      注解介绍: Spring AOP切点表达式用法总结 - 爱宝贝丶 - 博客园 (cnblogs.com)

      切面形参介绍:@Aspect 切面注解使用 - 秃了也变强了 - 博客园 (cnblogs.com)

      拦截器执行的顺序:

      1. try {
      2. Object result = null;
      3. try {
      4. System.out.println("@Around通知start");
      5. System.out.println("@Before通知!");
      6. result = service4.say("路人");
      7. System.out.println("@Around绕通知end");
      8. return result;
      9. } finally {
      10. System.out.println("@After通知!");
      11. }
      12. System.out.println("@AfterReturning通知!");
      13. return retVal;
      14. } catch (Throwable ex) {
      15. System.out.println("@AfterThrowing通知!");
      16. //继续抛出异常
      17. throw ex;
      18. }

    155. 相关阅读:
      mysql是怎么运行的-笔记
      WIN11任务栏出现空白,卡任务栏的解决办法
      【学习笔记】DDD领域驱动设计篇
      做闲鱼如何提升曝光量?
      C程序设计(谭浩强)第五版课后题答案 第一章
      高等数学基础概念的Python开发实现
      Aspose.Words 操作 Word 画 EChart 图
      如何利用IP地址定位保护网络安全?
      C习题002:澡堂洗澡
      【多目标优化算法MOAHA】多目标人工蜂鸟算法(Matlab代码实现)
    156. 原文地址:https://blog.csdn.net/qq_34922830/article/details/127044190