首页 > 其他分享 >SpringAOP

SpringAOP

时间:2023-10-02 16:35:44浏览次数:44  
标签:逻辑 代码 代理 AOP SpringAOP 方法 Advice

Spring AOP原理深层解析

前言

IOC和AOP是Spring的两个重要组成部分,IOC之前也经过分析(点击跳转)可以抽象认为这是一个容器,那AOP又是什么东西呢?

AOP是Aspect-Oriented Programming(面向方面编程或者面向切面)的简称。它可以看成是OOP(面向对象编程)的一种延续。简单地说就是将代码中重复的部分抽取出来,在需要执行的时候使用动态代理技术,在不修改源码的基础上对方法进行增强。

AOP的知识点特别多,这里简单整理一些比较重要的知识点概念。如果需要深度学习下去,可以参考源码分析:推荐阅读

什么是AOP?

(这里主要是摘录https://gyl-coder.top/spring/spring-ioc-aop/)

下面我们先看一个 OOP 的例子。

例如:现有三个类,HorsePigDog,这三个类中都有 eat 和 run 两个方法。

通过 OOP 思想中的继承,我们可以提取出一个 Animal 的父类,然后将 eat 和 run 方法放入父类中,HorsePigDog通过继承Animal类即可自动获得 eat()run() 方法。这样将会少些很多重复的代码。

OOP 编程思想可以解决大部分的代码重复问题。但是有一些问题是处理不了的。比如在父类 Animal 中的多个方法的相同位置出现了重复的代码,OOP 就解决不了。

/**
 * 动物父类
 */
public class Animal {

    /** 身高 */
    private String height;

    /** 体重 */
    private double weight;

    public void eat() {
        // 性能监控代码
        long start = System.currentTimeMillis();

        // 业务逻辑代码
        System.out.println("I can eat...");

        // 性能监控代码
        System.out.println("执行时长:" + (System.currentTimeMillis() - start)/1000f + "s");
    }

    public void run() {
        // 性能监控代码
        long start = System.currentTimeMillis();

        // 业务逻辑代码
        System.out.println("I can run...");

        // 性能监控代码
        System.out.println("执行时长:" + (System.currentTimeMillis() - start)/1000f + "s");
    }
}

这部分重复的代码,一般统称为 横切逻辑代码

横切逻辑代码存在的问题:

  • 代码重复问题
  • 横切逻辑代码和业务代码混杂在一起,代码臃肿,不变维护

AOP 就是用来解决这些问题的

AOP 另辟蹊径,提出横向抽取机制,将横切逻辑代码和业务逻辑代码分离

代码拆分比较容易,难的是如何在不改变原有业务逻辑的情况下,悄无声息的将横向逻辑代码应用到原有的业务逻辑中,达到和原来一样的效果。

AOP 解决了什么问题

通过上面的分析可以发现,AOP 主要用来解决:在不改变原有业务逻辑的情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。

AOP 为什么叫面向切面编程

:指的是横切逻辑,原有业务逻辑代码不动,只能操作横切逻辑代码,所以面向横切逻辑

:横切逻辑代码往往要影响的是很多个方法,每个方法如同一个点,多个点构成一个面。这里有一个面的概念

重要术语

连接点(Join point):

  • 能够被拦截的地方:Spring AOP是基于动态代理的,所以是方法拦截的。每个成员方法都可以称之为连接点~

切点(Poincut):

  • 具体定位的连接点:上面也说了,每个方法都可以称之为连接点,我们具体定位到某一个方法就成为切点

增强/通知(Advice):

  • 表示添加到切点的一段逻辑代码,并定位连接点的方位信息

    • 简单来说就定义了是干什么的,具体是在哪干
    • Spring AOP提供了5种Advice类型给我们:前置、后置、返回、异常、环绕给我们使用!
  • 五种Advice类型如下:

    • 前置通知(Before Advice): 在连接点之前执行的Advice,不过除非它抛出异常,否则没有能力中断执行流。使用 @Before 注解使用这个Advice。
    • 返回之后通知(After Retuning Advice): 在连接点正常结束之后执行的Advice。例如,如果一个方法没有抛出异常正常返回。通过 @AfterReturning 关注使用它。
    • 抛出(异常)后执行通知(After Throwing Advice): 如果一个方法通过抛出异常来退出的话,这个Advice就会被执行。通用 @AfterThrowing 注解来使用。
    • 后置通知(After Advice): 无论连接点是通过什么方式退出的(正常返回或者抛出异常)都会执行在结束后执行这些Advice。通过 @After 注解使用。
    • 围绕通知(Around Advice): 围绕连接点执行的Advice,就你一个方法调用。这是最强大的Advice。通过 @Around 注解使用。

织入(Weaving):

  • 增强/通知添加到目标类的具体连接点上的过程。

引入/引介(Introduction):

  • 引入/引介允许我们向现有的类添加新方法或属性。是一种特殊的增强!

切面(Aspect):

  • 切面由切点和增强/通知组成,它既包括了横切逻辑的定义、也包括了连接点的定义。

底层实现

我们上面介绍了AOP的一系列相关术语,而这些术语其实也就是为了加深我们对AOP的面向切面的认识。AOP的底层其实是通过动态代理来实现的,其实如果学过设计模式其实看着AOP的思想也能大概猜出来了。将相同逻辑的重复代码横向抽取出来,使用动态代理技术将这些重复代码织入到目标对象方法中,实现和原来一样的功能

在SpringAOP中,我们底层的通过两种动态代理来实现的,分别是JDK动态代理和CGLib动态代理。

JDK动态代理

关于JDK的动态代理代码演示可以看一下我的这一篇,顺便也可以了解一下动态代理模式(点击跳转

JDK动态代理是需要实现某个接口了,而我们类未必全部会有接口,于是CGLib代理就有了~~

  • CGLib代理其生成的动态代理对象是目标类的子类
  • Spring AOP默认是使用JDK动态代理,如果代理的类没有接口则会使用CGLib代理。

那么JDK代理和CGLib代理我们该用哪个呢??在《精通Spring4.x 企业应用开发实战》给出了建议:

  • 如果是单例的我们最好使用CGLib代理,如果是多例的我们最好使用JDK代理

原因:

  • JDK在创建代理对象时的性能要高于CGLib代理,而生成代理对象的运行性能却比CGLib的低。
  • 如果是单例的代理,推荐使用CGLib

CGLib动态代理

字节码生成技术实现AOP,其实就是继承被代理对象,然后Override需要被代理的方法,在覆盖该方法时,自然是可以插入我们自己的代码的。CGLib动态代理需要依赖asm包,把被代理对象类的class文件加载进来,修改其字节码生成子类。

因为需要Override被代理对象的方法,所以自然CGLIB技术实现AOP时,就 必须要求需要被代理的方法不能是final方法,因为final方法不能被子类覆盖 。

现在演示一下如何使用CGLIB动态代理实现开头的情景,CGLIB动态代理不要求被代理类实现接口,先写一个被代理类。

public class MonkeyOperation {
    public void put() {
        System.out.println("放入猴子...");
    }
 
    public void get() {
        System.out.println("拿出猴子...");
    }
}

在写一个类实现MethodInterceptor接口,并在接口方法intercept()里对被代理对象的方法做增强,并编写生成代理对象的方法

public class FridgeCGLibProxy implements MethodInterceptor {
 
    public String name="hahaha";
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        openDoor();//调用被代理方法做一些操作
        Object result = methodProxy.invokeSuper(proxy,args);//执行被代理对象的方法,如果方法有返回值则赋值给result
        closeDoor();//调用被代理方法后做一些操作
        return result;
    }
    private void openDoor(){
        System.out.println("打开冰箱...");
    }
    private void closeDoor(){
        System.out.println("关闭冰箱...");
    }
    public Object getProxy(Class cls){//参数为被代理的类对象
        Enhancer enhancer = new Enhancer();//创建增强器,用来创建动态代理类
        enhancer.setSuperclass(cls);//设置父类,即被代理的类对象
        enhancer.setCallback(this);//设置回调,指定为当前对象
        return enhancer.create();//返回生成的代理类
    }
}

测试及结果:

  public static void main(String args[]) {
      MonkeyOperation monkeyOperation =(MonkeyOperation)new FridgeCGLibProxy().getProxy(MonkeyOperation.class);
      monkeyOperation.put();
      monkeyOperation.get();
  }

应用场景

通过使用SpringAOP,我们可以将我们与业务无关的代码,分割出来。具体的应用场景主要是有这些:

  1. 权限控制
  2. 缓存控制
  3. 事务控制
  4. 审计日志
  5. 性能监控
  6. 分布式追踪
  7. 异常处理

如何在这些场景去使用就需要根据情况具体实践了。可以多看看实战书籍!

参考资料

SpringAOP就是这么简单啦

https://gyl-coder.top/spring/spring-ioc-aop/

Spring中的AOP原理

《Spring技术内幕:深入解析Spring架构与原理》

上一篇Linux IO模型知识梳理 下一篇详解SpringMVC的工作原理  

本文作者:CryFace

本文链接:https://www.cnblogs.com/CryFace/p/13646924.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

分类: 标签: , 好文要顶 关注我 收藏该文 CryFace
粉丝 - 30 关注 - 23
    +加关注 0 0       « 上一篇: Linux IO模型知识梳理
» 下一篇: 详解SpringMVC的工作原理

标签:逻辑,代码,代理,AOP,SpringAOP,方法,Advice
From: https://www.cnblogs.com/zhou111f/p/17740028.html

相关文章

  • Spring 04 SpringAOP 切面编程
    Aop:面向切面,在不修改代码的前提下对方法进行增强 pom.xml<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version>......
  • 基于注解的AOP日志切面控制SpringAOP
    1.配置注解(作用于方法上,相当于要告诉aop对哪些方法做切面植入)importjavax.jdo.annotations.Element;importjava.lang.annotation.*;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceAspectPointCutTag{Stringnam......
  • @Around简单使用示例——SpringAOP增强处理
    @Around简单使用示例——SpringAOP增强处理@Around的作用既可以在目标方法之前织入增强动作,也可以在执行目标方法之后织入增强动作;可以决定目标方法在什么时候执行,如何执行,甚至可以完全阻止目标目标方法的执行;可以改变执行目标方法的参数值,也可以改变执行目标方法之后的返回......
  • JDK 动态代理 和 CGLIB 动态代理 的区别【SpringAOP】
    一、原理区别(版本一)Java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认......
  • SpringAOP
    一、proxy增强1、基于JDKjava自带的代理功能,只能针对接口,目标类与代理类为平级关系publicclassJDKProxy{ interfaceFoo{ voidfoo(); } staticclassTargetimplementsFoo{ publicvoidfoo(){ System.out.println("targetfoo"); } } publicstaticvo......
  • springAOP
    一,AOP1,面向切面编程AspectOrientedProgramming2,编程思想的发展路程①Logicjava:java逻辑编程②OOP:面向对象编程③OIP:interface面向接口编程④面向配置文件编程以上的思想,都是逐步升级的概念⑤AOP在OOP的基础上,增强了OOP的功能3,实现方式①基于配置(xml......
  • 对SpringIOC和SpringAOP的理解
    SpringIOC和SpringAOP是Spring的两个核心组件。SpringIOC:SpringIOC是一个管理bean的容器,能够帮我们管理bean的整个生命周期,在没有SpringIOC的时候,我们需要自己手动的管理bean以及bean的依赖关系,这样会增加耦合,而有了SpringIOC,它能帮我们管理bean以及bean的依赖关系,使得代码解耦。......
  • SpringAOP精简版
    AOP简介概念:AOP是一种编程范式作用:做无入侵式增强程序功能Spring是如何实现AOP的?1.导坐标2.在Spring核心配置类上添加开启SpringAOP驱动注解3.定义通知类,@Component,@Aspect4.添加切入点,@PointCut5.制作通知,@Before等SpringAOP执行流程1.启动Spring容器2.读取切......
  • SpringAOP【Web后端开发进阶】
    AOP(思想):面向切面编程思想的实现:动态代理 动态代理的2种实现方式:1、基于接口的JDK动态代理2、基于子类的CGLIB动态代理 AOP思想的作用:1、在不改变原程序代码的前提下,对方法功能增强2、像添加插件一样,任意插拔。(程序更加灵活)......
  • SpringIOC和SpringAOP
    作为一个Spring使用者条件:拥有深入的Spring框架知识和开发经验,能够熟练地运用Spring框架来构建复杂的应用程序。了解Spring框架的核心概念和设计思想,如控制反转(IoC)、依赖注入(DI)、面向切面编程(AOP)等,并能灵活运用这些概念来解决实际问题。熟悉Spring框架中各个模块的功能和用法,如......