AOP 组件

Aspact

  • AspectJ:横切关注点的单元模块,类似于Java class 。它有独特的编译器 Compiler,重新编译字节码
  • CGLib : 在运行的时候生成字节码,不会重新编译。也就是说是动态加载的
  • Spring AOP :多个类之间的关注模块,组织的形式,里边包含横切的一些类或者方法。

Join point (横切点)

  • AspectJ:一个方法 或者一个异常的处理,具体的某个执行的点
  • Spring AOP :Aspact 属于一种组织模式(如类), 做为模块来组织 join point (具体的某个执行的点),然后 pointcut 来进行筛选,接下来由 advice 进行具体的动作。

Pointcut

  • AspectJ :匹配 join point 筛选方式
  • Spring AOP :Join point 的限制条件,判断哪个连接点可以接拦截器

Advice 通知/动作

  • AspectJ : 一段代码,一个程序。在目标代码执行前后的一个动作
  • Spring AOP : around (拦截、主动),before and after(被动),采用拦截器方式,可以有一串的拦截器在Join point上

Introduction 介绍

  • AspectJ : 运行时或编译时动态的继承某个接口或者某个类
  • Sping AOP : 辅助的类,在某个特点的类上面

AOP 的设计模式

  • 代理模式:静态代理、静态代理
  • 判断模式:类、方法、注解、参数、异常
  • 拦截模式:前置、后置、返回、异常

Java静态代理

  1. // 公共类和方法
  2. public interface EchoService {
  3. String echo (String message);
  4. }
  5. public class DefaultEchoServiceImpl implements EchoService{
  6. @Override
  7. public String echo(String message) {
  8. return "echo " + message;
  9. }
  10. }
  • 常用 oop 继承和组合相结合
  1. public class ProxyEchoService implements EchoService{
  2. private final EchoService echoService;
  3. public ProxyEchoService(EchoService echoService) {
  4. this.echoService = echoService;
  5. }
  6. @Override
  7. public String echo(String message) {
  8. long startTime = System.currentTimeMillis();
  9. String result = echoService.echo(message);
  10. long costTime = System.currentTimeMillis() - startTime;
  11. System.out.println("echo 方法的执行时间:" + costTime + " ms");
  12. return result;
  13. }
  14. }
  15. /**
  16. * 静态代理:
  17. * 组合和继承的模式相结合
  18. */
  19. public class StaticProxyDemo {
  20. public static void main(String[] args) {
  21. EchoService echoService = new ProxyEchoService(new DefaultEchoServiceImpl());
  22. String echo = echoService.echo("Hello,word!");
  23. System.out.println("echo result : " + echo);
  24. }
  25. }

Java动态代理

  • JDK 动态代理
  1. package com.example.demo.aop;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. /**
  6. * JDK 动态代理
  7. */
  8. public class JdkDynamicProxyDemo {
  9. public static void main(String[] args) {
  10. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  11. Object proxyInstance = Proxy.newProxyInstance(classLoader, new Class[]{EchoService.class}, new InvocationHandler() {
  12. @Override
  13. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  14. if (EchoService.class.isAssignableFrom(method.getDeclaringClass())) {
  15. EchoService echoService = new ProxyEchoService(new DefaultEchoServiceImpl());
  16. return echoService.echo((String) args[0]);
  17. }
  18. return null;
  19. }
  20. });
  21. EchoService echoService = (EchoService) proxyInstance;
  22. echoService.echo("hello,word!");
  23. }
  24. }
  • 字节码提升,如 CGLIB

Java AOP 判断模式

判断来源

  • 类型
  • 方法
  • 注解
  • 参数
  • 异常
  1. package com.example.demo.aop;
  2. import org.springframework.util.ReflectionUtils;
  3. import java.lang.reflect.Method;
  4. /**
  5. * AOP 目标过滤示例
  6. *
  7. * 通过Java反射 API 判断
  8. */
  9. public class TargetFileDemo {
  10. public static void main(String[] args) throws ClassNotFoundException {
  11. String targetClassName = "com.example.demo.aop.EchoService";
  12. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  13. Class<?> targetClass = classLoader.loadClass(targetClassName);
  14. //方法定义 - 采用Spring 的 util 获取方法
  15. Method echo = ReflectionUtils.findMethod(targetClass, "echo", String.class);
  16. System.out.println(echo);
  17. //查找方法 throws 类型为 NullPointerException
  18. ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
  19. @Override
  20. public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
  21. System.out.println("仅抛出 NullPointerException 方法:" + method);
  22. }
  23. }, new ReflectionUtils.MethodFilter() {
  24. @Override
  25. public boolean matches(Method method) {
  26. Class<?>[] parameterTypes = method.getParameterTypes();
  27. Class<?>[] exceptionTypes = method.getExceptionTypes();
  28. return exceptionTypes.length == 1
  29. && NullPointerException.class == exceptionTypes[0]
  30. && parameterTypes.length == 1
  31. && String.class == parameterTypes[0];
  32. }
  33. });
  34. }
  35. }

Java AOP 拦截模式

拦截类型

  • 前置拦截
  • 后置拦截
  • 异常拦截
  • 环绕拦截

Spring AOP 功能概述

核心特性

  • 纯Java实现,无编译时特殊处理、不修改和控制ClasssLoader
  • 仅支持方法级别的 Join Points
  • 非完整AOP实现框架
  • Spring IOC 容器整合
  • AspectJ 注解驱动整合(非竞争关系)

Spring AOP 编程模型

注解驱动

  • 实现 Enable 模块驱动,@EnableAspectJAutoProxy
  • 注解

Spring AOP 设计目标

  • 整体目标:不是要完整的实现AOP的框架,而是整合AspectJ.

自动动态代理

  1. import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
  2. import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
  3. import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;