003.Spring AOP的原理——Spring AOP简介——AOP的核心概念——AOP的2种代理方式——AOP的5种通知类型

1.6 Spring AOP原理

Spring AOP通过面向切面技术将与业务无关却为业务模块所共用的逻辑代码封装起来,以提高代码的复用率,降低模块之间的耦合度。
Spring AOP将引用分为核心关注点和横切关注点两个部分。业务处理流程为核心关注点,被业务说依赖的公共部分为横切关注点。横切关注点的特点是其行为经常发生在核心关注点的多处,而多处操作基本相似,比如权限认证、日志、事务。AOP的核心思想是将:核心关注点和横切关注点分离开来,以降低模块耦合度。Spring AOP的主要应用如下:

1.6.2 Spring AOP的2种代理模式

Spring 提供了JDK和CGLib2种方式来生成代理对象,具体生成代理对象的方式由AopProxyFactory根据AdvisedSupport对象的配置来决定。Spring默认的代理对象生成策略为:如果是目标类接口,则使用JDK动态代理技术,否则使用CGLib动态代理技术。

  • JDK动态代理主要通过 java.lang.reflect 包中 Proxy 类和InvocationHandler接口来实现。InvocationHandler是一个接口,不同的实现类定义不同的横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编制在一起。Proxy 类利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。JDK 1.8中Proxy类的定义如下:
public class Proxy implements java.io.Serializable{
  private static final long serialVersionUID = -2222568056686623797L;
  // 1: 在构造方法参数中定义不同的InvocationHandler实现类
  private static final Class<?>[] constructorParams = {
    InvocationHandler.class};
  //2:Proxy类缓存列表
  private static final WeakCache<ClassLoader,Class<?>[],Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(),new ProxyClassFactory());
   //3:当前代理需要调用的Handler实例对象(该对象需要经过序列化)
   protected InvocationHandler h;
   // ... ... 此处省略部分实现代码
   //4.Proxy类构造函数,参数InvocationHandler为当前代理的对象
   protected Proxy(InvocationHandler h){
       Objects.requireNonNull(h);
       this.h = h;
   }
   ... ...
}
  • CGLib动态代理:CGLib即Code Generation Library,它是一个高性能的代码生成类库,可以在运行期间扩展Java类和实现java接口。CGLib包的底层通过字节码处理框架ASM来实现,通过转换字节码生成新的类。
  • CGLib动态代理和JDK动态代理的区别:JDK只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则只能通过CGLib创建动态代理来实现。

1.6.4 AOP的5种通知类型

Spring AOP有5种通知类型,具体如下表所示:

1.6.5 AOP的代码实现

在Spring 中,AOP的使用比较简单,如下代码通过@Aspect注解声明一个切面,通过@Pointcut定义需要拦截的方法,然后用@Before、@AfterReturning、@Around、分别实现前置通知、后置通知和环绕通知的方法。

@Aspect // step 1: 定义切面
public class TransactionDemo{
  //step 2:定义要拦截的方法
  @Pointcut(value = "exception(* com.alex.core.service.*.*.*.(..))")
  public void point(){
  }
  @Before(value = "point()") // step 3:定义前置通知
  public void before(){
    System.out.println("transaction begin");
  }
  @AfterReturning(value = "point()") // step 4:定义后置通知
  public void after(){
    System.out.println("transaction commit");
  }
  @Around("point()") // step 5:定义环绕通知
  public void around(ProceedingJoinPoint joinPoint) throws Throwable{
    System.out.println("transaction begin");
    joinPoint.proceed();
    System.out.println("transaction commit!);
  }
}
posted @ 2022-10-01 19:53  ╰(‵□′)╯  阅读(37)  评论(0编辑  收藏  举报