深度分析springaop,一文带你彻底搞懂springaop底层原理!

前程有光      2022-06-05     578

关键词:

SpringAOP

我们为什么要使用AOP(面向切面编程)?当我们在现实中完成实际的项目时,我们总是需要在一个“动作”进行前,进行中,或进行后进行一些操作,比如当我们在运行程序时,我们想要进行日志保存,或者在每一个方法调用后输出一句话,这就表示我们每一次进行一个“动作”都需要进行同样的操作,这就导致程序员会进行大量的、无用的重复性动作,面对这种情况,AOP应运而生。

AOP概述

AOP,即Aspect Oriented Rrogramming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能统一维护的一种技术。AOP可以对业务漏极的各个部分进行隔离,从而使得业务逻辑之间得耦合性降低,提高程序得可重用性,同时提高了开发得效率。

AOP和OOP是两种不同的设计思想。OOP(面向对象编程)针对业务处理过程得实体及其属性和行为进行抽象封装,获得清晰高效得逻辑单元划分。AOP则是针对业务处理过程中得切面进行提取,是面对业务处理过程中的某个步骤或阶段,获得逻辑过程中各部分之间低耦合性得隔离效果。

面向切面编程的好处就是:减少重复,专注业务。它是面向对象编程的一种补充。
个人整理了一些资料,有需要的朋友可以直接点击领取。

Java基础知识大全

22本Java架构师核心书籍

从0到1Java学习路线和资料

1000+道2021年最新面试题

核心原理及使用案例

原理:使用动态代理的方式在执行方法前后或出现异常时加入相关的逻辑。

使用:

事务处理:开启事务,关闭事务,出现异常回滚事务.....
权限判断:执行方法前,判断是否具有权限;
日志处理;
......
事务处理:开启事务,关闭事务,出现异常回滚事务.....
权限判断:执行方法前,判断是否具有权限;
日志处理;
......

AOP的基本概念(Spring的专业术语)

0.增强:向各个程序内部注入一些逻辑代码从而增强原有程序的功能。

1.连接点(JoinPoint):类中可以被增强的方法,这个方法就就被称为连接点,切记连接点并不是一定会被增强。

2.切入点(Pointcut):类中实际被增强的方法。

3.通知(Advice):指一个切面在特定的连接点要做的事情,简单来说就是“增强”。可以分为方法执行前通知,方法执行后通知,环绕通知等等。

4.切面(Aspect):把通知添加到切入点的过程就叫切面。

5.目标(Target):代理的目标对象,即要增强的方法所在的类。

6.代理(Proxy):向目标对象应用通知之后创建的代理对象。

SpringAOP实现

很多的框架都对AOP这种编程思想进行了实现。Spring只是其中的一种,可以完成面向切面编程。AspectJ也是一个面向切面的框架,并且实现方式更为简捷,更为方便,并且支持注解式开发。所以,Spring又将AspectJ对于AOP的实现引入到自己的框架之中。

Spring中使用AOP开发时,通常使用AspectJ的实现方式。其中常用的通知有五种类型:

  • 前置通知:方法执行前执行;
  • 后置通知:方法执行后执行;
  • 环绕通知:前后都执行;
  • 异常通知:出异常时通知;
  • 最终通知:如return后执行。

SpringAOP的使用

导入实现AOP的AspectJ的jar

<!--Spring实现AOP是依靠Aspects框架实现-->
<!--Aspects相关jar-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

基于AspectJ的xml配置实现

所有的配置都在spring.xml文件中进行。

1.创建一个增强功能的类。

import org.aspectj.lang.ProceedingJoinPoint;
//通知(Advice):在连接点要做的事情
public class Aop {

    public void doLog() {
        System.out.println("=====保存日志=====");
    }

    public void commit() {
        System.out.println("=====提交事务=====");
    }

    public void around(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("======方法前通知======");
        try {
            proceedingJoinPoint.proceed();//调用自己的方法
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("======方法后通知======");
    }

    public void throwable(Throwable throwable) {
        System.out.println("======出异常了======");
        System.out.println(throwable.getMessage());
    }
}

2.将装有增强功能的类交给交由spring管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--把装有通知(Advice)的类交给Spring管理-->
    <bean id="aop" class="com.cwd.spring4pro.demo1.aop.Aop"></bean>
    
    <!--在这里进行织入,即切面(Aspect):将通知添加到切入点-->

</beans>

3.配置切面(Aspect)

先准备一个被增强的类,即目标(Target)

import org.springframework.stereotype.Component;

//目标(Target):代理的目标对象,即要增强的类
@Component(value = "target")
public class Target {
    /*
    连接点(Joinpoint),可以被增强的方法
    切入点(pointcut),实际被增强的方法,被增强了
    */
    public void pointCut() {
        System.out.println("这是一个保存的操作!!!");
        return;
    }
}

将通知添加到切入点。

<!--织入-->
    <aop:config>
        <!--
        配置切入点 
        execution表达式 前*表示返回值 saveUser(..)表示要增强的方法 ..表示参数
        -->
        
        <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>

        <!--配置通知 ref中引用的是通知类的id-->
        <aop:aspect ref="aop">
        
           <!--前置通知-->
           <aop:before method="doLog" pointcut-ref="pointCut"/>

        </aop:aspect>
    </aop:config>

五种通知类型配置

1.前置通知

<!--织入-->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!--前置通知-->
        <aop:before method="doLog" pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>

2.后置通知

<!--织入-->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!--后置通知-->
        <aop:after method="commit" pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>

3.环绕通知

<!--织入-->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!--环绕通知-->
        <aop:around method="around" pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>

4.异常通知

public void pointCut() {
    System.out.println("这是一个保存的操作!!!");
    int a = 10 / 0;
    return;
}

<!--织入-->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!--异常通知-->
        <aop:after-throwing method="throwable" pointcut-ref="pointCut" throwing="throwable"/>
    </aop:aspect>
</aop:config>

5.最终通知

<!--织入-->
<aop:config>
    <aop:pointcut id="pointCut" expression="execution(* com.cwd.spring4pro.demo.Target.pointCut(..))"/>
    <aop:aspect ref="aop">
        <!--最终通知-->
        <aop:after-returning method="commit" pointcut-ref="pointCut"/>
    </aop:aspect>
</aop:config>

最终通知一般在return之后执行。

注解实现

开启aop注解扫描

<!--开启注解标签-->
<aop:aspectj-autoproxy/>

在通知类中进行配置,如下所示:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component//将这个类交给Spring管理
@Aspect//标注这个类时装有通知的类
public class Aop {

    @Before("execution(* com.cwd.spring4pro.demo.Target.pointCut(..))")
    public void doLog() {
        System.out.println("=====保存日志=====");
    }

    @After("execution(* com.cwd.spring4pro.demo.Target.pointCut(..))")
    public void commit() {
        System.out.println("=====提交事务=====");
    }

    public void around(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("======方法前通知======");
        try {
            proceedingJoinPoint.proceed();//调用自己的方法
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("======方法后通知======");
    }


    @AfterThrowing(value = "execution(* com.cwd.spring4pro.demo.Target.pointCut(..))",throwing = "throwable")
    public void throwable(Throwable throwable) {
        System.out.println("======出异常了======");
        System.out.println(throwable.getMessage());
    }

    @AfterReturning("execution(* com.cwd.spring4pro.demo.Target.pointCut(..))")
    public  void returnAfter() {
        System.out.println("======return后=====");
    }
}

最后

都看到这里了,觉得文章对你有帮助的话记得点个赞,感谢支持!

一文带你彻底搞懂springboot-rabbitmq(代码片段)

一、环境搭建采用maven多module模式,共计创建三个子modulecommon:通用实体信息rabbitmq-publisher:消息发布者,基于SpringBootrabbitmq-subscriber:消息订阅者,基于SpringBoot在消息发布者和订阅者两个项目中加入rabbitm... 查看详情

一文带你搞懂内存泄漏!!!(代码片段)

好文推荐:作者:codelang检测内存是否泄漏非常简单,只要在任意位置调用Debug.dumpHprofData(file)即可,通过拿到hprof文件进行分析就可以知道哪里产生了泄漏,但dump的过程会suspend所有的java线程,导致用户界... 查看详情

一文搞懂springaop源码底层原理

...落到代码的各个部分,难以维护。一键获取源码地址springaop面试题AOP就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。二、AOP的应用场景·日志记录·权限验证·效率检查·事务管理三、SpringAOP原理及其 查看详情

图文并茂!!!一文搞懂springaop(面向切面编程)(代码片段)

文章目录SpringAOPAOP概述核心原理及使用案例AOP的基本概念(Spring的专业术语)SpringAOP实现SpringAOP的使用导入实现AOP的AspectJ的jar基于AspectJ的xml配置实现五种通知类型配置注解实现SpringAOP我们为什么要使用AOP(面向切面... 查看详情

mybatis缓存专题-一文彻底搞懂mybatis一级缓存(代码片段)

文章目录1.缓存的概念1.1.什么是缓存1.2.为什么使用缓存1.3.什么样的数据能使用缓存,什么样的数据不能使用2.什么是一级缓存3.什么情况下会命中一级缓存4.Mybatis的一级缓存机制详解5.MyBatis关闭一级缓存6.Mybatis的一级缓存机... 查看详情

mybatis缓存专题-一文彻底搞懂mybatis一级缓存(代码片段)

文章目录1.缓存的概念1.1.什么是缓存1.2.为什么使用缓存1.3.什么样的数据能使用缓存,什么样的数据不能使用2.什么是一级缓存3.什么情况下会命中一级缓存4.Mybatis的一级缓存机制详解5.MyBatis关闭一级缓存6.Mybatis的一级缓存机... 查看详情

一文带你掌握springaop的底层实现

SpringAOP底层实现springaop中的joinpoint前面讲过多种类型的joinpoint,如构造方法调用、字段的设置即获取、方法调用、方法执行等,但是在springaop中之实现了方法级别的joinpoint,确切来说是只支持方法执行类型的joinpoint。... 查看详情

一文带你彻底搞懂docker中的cgroup(代码片段)

前言进程在系统中使用CPU、内存、磁盘等计算资源或者存储资源还是比较随心所欲的,我们希望对进程资源利用进行限制,对进程资源的使用进行追踪。这就让cgroup的出现成为了可能,它用来统一将进程进行分组࿰... 查看详情

一文带你掌握springaop的底层实现(代码片段)

SpringAOP底层实现springaop中的joinpoint前面讲过多种类型的joinpoint,如构造方法调用、字段的设置即获取、方法调用、方法执行等,但是在springaop中之实现了方法级别的joinpoint,确切来说是只支持方法执行类型的joinpoint。... 查看详情

一文带你认识springaop(代码片段)

SpringAOP简介AOP(Aspect-OrientedProgramming:面向切面编程)是对OOP(Object-OrientedProgramming:面向对象编程)的补充和完善。OOP引入封装、继承和多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。封装就要求将功能分散到... 查看详情

从源码入手,一文带你读懂springaop面向切面编程

之前《零基础带你看Spring源码——IOC控制反转》详细讲了Spring容器的初始化和加载的原理,后面《你真的完全了解Java动态代理吗?看这篇就够了》介绍了下JDK的动态代理。基于这两者的实现上,这次来探索下Spring的AOP原理。虽... 查看详情

一文彻底搞懂zookeeper(代码片段)

本文是基于CentOS7.9系统环境,进行Zookeeper的学习和使用1.Zookeeper简介1.1什么是ZookeeperZookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。本质上,就是文件系统+通知机制1.2Zookeeper工作机制Zookeepe... 查看详情

一文彻底搞懂zookeeper(代码片段)

本文是基于CentOS7.9系统环境,进行Zookeeper的学习和使用1.Zookeeper简介1.1什么是ZookeeperZookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。本质上,就是文件系统+通知机制1.2Zookeeper工作机制Zookeepe... 查看详情

一文彻底搞懂slam技术(代码片段)

什么是SLAM?SLAM (simultaneouslocalizationandmapping),也称为CML(ConcurrentMappingandLocalization),即时定位与地图构建,或并发建图与定位。问题可以描述为:将一个机器人放入未知环境中的未知位置,是否有办法让机器人一边逐步描... 查看详情

一文彻底搞懂slam技术(代码片段)

什么是SLAM?SLAM (simultaneouslocalizationandmapping),也称为CML(ConcurrentMappingandLocalization),即时定位与地图构建,或并发建图与定位。问题可以描述为:将一个机器人放入未知环境中的未知位置,是否有办法让机器人一边逐步描... 查看详情

一文彻底搞懂前端沙箱(代码片段)

什么是“沙箱”沙箱(Sandbox)[1]也称作:“沙箱/沙盒/沙盘”。沙箱是一种安全机制,为运行中的程序提供隔离环境。通常是作为一些来源不可信、具破坏力或无法判定程序意图的程序提供实验之用。沙箱能够安全的执行不受信... 查看详情

一文彻底搞懂docker中的namespace(代码片段)

什么是namespacenamespace是对全局系统资源的一种封装隔离。这样可以让不同namespace的进程拥有独立的全局系统资源。这样改变一个namespace的系统资源只会影响当前namespace中的进程,对其它namespace中的资源没有影响。以前Linux也... 查看详情

深度学习计算机指令系统,彻底搞懂指令十大寻址方式

系列文章目录1.《带你深挖计算机底层逻辑,打通你计算机基础知识的任督二脉》2.《深度学习计算机底层原理,深度剖析存储器》3.《基于内存全面理解高速缓冲存储器》4.《深度学习计算机指令系统,彻底搞懂指令... 查看详情