Spring系列篇--关于AOP【面向切面】的详解

news2024/11/24 1:44:46

目录

一.AOP是什么

二.案例演示 

1.前置通知1.1 先准备接口

1.2然后再准备好实现类

1.3对我们的目标对象进行JavaBean配置 

1.4 编写前置系统日志通知

1.5配置系统通知XML中的JavaBean

1.6 配置代理XML中的JavaBean

1.7 测试代码开始测试

注意这里有一个报错问题!!!

2. 后置通知2.1 先准备好后置通知的系统日志

2.2 配置后置系统通知的XML的JavaBean

 2.3 测试结果

3.环绕通知

3.2 环绕通知的系统日志

3.3 配置环绕通知的XML的JavaBean与前置通知和后置通知一致

3.4 测试结果

4.异常通知4.1 异常通知的系统日志和其他系统日志不同的是,方法名为固定的afterThrowing,不能修改

5.过滤通知5.1 直接在XML中配置JavaBean

四.总结aop是面向切面编程,普通程序由上而下正常执行,aop的程序执行是先执行到目标对象的目标方法中,如果连接点上由前置通知,则先执行前置通知再执行目标方法,最后如果目标方法有后置通知则最后执行后置通知代码,不管是前置通知,后置通知,环绕通知,异常通知,过滤通知,代码都是非业务核心代码,如日志、事务的管理(开启、提交、回滚)         


一.AOP是什么

简介:
面向切面编程(Aspect-Oriented Programming)是一种编程范式,它的主要目的是通过预编译和运行期动态代理实现程序功能的横切(cross-cutting)特性,如日志记录、性能统计、事务监控等。它可以帮助开发者将这些原本分散在各个方法或类中的业务逻辑抽象出来,提高代码复用性,降低耦合度
AOP(Aspect-Oriented Programming)是Spring框架的一个重要特性,它通过将横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来,以模块化的方式在整个应用程序中重复使用。以下是关于AOP的简介及其特点:

AOP是一种编程范式,它通过将横切关注点切割出来,将其模块化,并将其应用于多个类和模块,以提高代码的重用性和可维护性。
横切关注点是指与核心业务逻辑无关但存在于多个类或模块中的非功能性需求,例如日志记录、性能监控、事务管理等。
特点:

模块化:AOP允许将横切关注点从核心业务逻辑中提取出来,形成独立的切面(Aspect),使得关注点的逻辑可以独立于各个模块。
解耦:AOP通过解耦横切关注点与核心业务逻辑,使得它们可以独立演化和变化,提高了模块之间的松耦合程度。
重用性:AOP允许将切面应用于多个类和模块,从而实现了关注点的重用,避免了代码的重复编写。
可维护性:将横切关注点抽象为切面后,使得代码结构更清晰,易于理解和维护。
动态性:AOP可以在运行时动态地将切面应用到目标对象上,而不需要修改目标对象的源代码,增强了系统的灵活性和可扩展性。
多样性:Spring框架支持不同类型的切面编程,包括基于代理的AOP和基于字节码增强的AOP。这样可以选择最适合应用程序需求的AOP实现方式。
在Spring框架中,AOP的实现采用了代理模式和动态代理技术。Spring提供了多种AOP的实现方式,包括基于XML配置的AOP、基于注解的AOP和基于纯Java配置的AOP(JavaConfig)等,开发者可以根据具体需求选择适合的方式来配置和使用AOP。
 

面向切面:
1.专业术语
①目标对象:
专业解释:被通知(被代理)的对象

通俗理解:在书店中,商品就是目标。每个商品都有自己的属性(比如价格、名称、库存等)和行为(比如计算促销价格、更新库存等)。收银员通过扫描商品的条形码来与商品进行交互,调用商品的方法来获取商品信息以及执行一些操作。商品本身即代表了目标

②连接点:
专业解释:程序执行过程中明确的点,如方法的调用,或者异常的抛出

通俗理解:在书店中,我们可以将顾客结账的行为看作一个连接点

③通知:
专业解释:在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)

通俗理解:

前置通知(Before Advice):在切入点前执行的代码,在读者购买图书之前,我们可以记录读者购买的图书信息
后置通知(After Advice):在切入点后执行的代码,在读者购买图书之后,我们可以更新图书库存
环绕通知(Around Advice):在切入点前后都执行的代码,我们可以对读者进行额外的安全检查和记录日志
异常通知(After-Throwing Advice):异常通知是在切入点发生异常时执行的额外功能代码。假设当顾客购买商品的数量大于库存数量时,就会发生异常。我们希望在顾客购买商品时检查库存,并在发生异常时执行异常通知,向顾客显示错误信息并处理异常情况
过滤通知(After-Returning Advice):过滤通知是在切入点成功执行后执行的额外功能代码。假设我们有一个特殊会员组,他们在购买商品时可以获得额外的积分。我们可以使用过滤通知来筛选出这些特殊会员,并在成功购买后给他们添加积分
④代理:
专业解释:将通知应用到目标对象后创建的对象(代理=目标+通知)

通俗理解:在书店中,收银员是一个代理角色。他们既代表顾客与商品交互,又代表书店执行一些额外的任务。当顾客带着商品到收银台时,收银员会扫描每个商品的条形码,获取商品信息并计算总价。这里,收银员即充当了顾客与商品之间的代理角色,也充当了超市执行计算总价等额外任务的代理角色

⑤切入点:
专业解释:

多个连接点的集合,定义了通知应该应用到那些连接点 (也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)

通俗理解:在书店场景中,我们可能希望在计算折扣方法之前或之后记录日志和进行库存管理。这些切入点决定了我们在代码中操作的位置

⑥适配器:
专业解释:适配器是一个中间组件,用于将面向切面编程框架与原始的业务逻辑代码连接起来(适配器=通知(Advice)+切入点(Pointcut))

通俗理解:在书店场景中,适配器可以将代理对象与书店的购买图书业务逻辑连接起来,使得代理对象能够在购买图书的过程中添加额外的功能

2.代码演示
        在上面场景模拟的代码中,我们能够发现记录日志的代码基本相同,那么有没有可能将这部分的代码抽取出来进行封装,统一进行维护呢?同时也可以将日志代码和业务代码完全分离,解耦合

  那么我们便可以将业务方法中的非业务核心代码(日志记录)抽离出来形成一个横切面,并且将这个横切面封装成一个对象,将所有的记录日志的代码写到这个对象中,以实现与业务代码的分离,这便是面向切面编程的思想

2.1将记录日志的代码进行封装
 

三.案例演示 


1.前置通知
1.1 先准备接口

package com.lya.aop.biz;
 
public interface IBookBiz {
    // 购书
    public boolean buy(String userName, String bookName, Double price);
 
    // 发表书评
    public void comment(String userName, String comments);
}

1.2然后再准备好实现类

package com.lya.aop.biz.impl;
 
import com.YU.aop.biz.IBookBiz;
import com.YU.aop.exception.PriceException;
 
public class BookBizImpl implements IBookBiz {
 
    public BookBizImpl() {
        super();
    }
 
    public boolean buy(String userName, String bookName, Double price) {
        // 通过控制台的输出方式模拟购书
        if (null == price || price <= 0) {
            throw new PriceException("book price exception");
        }
        System.out.println(userName + " buy " + bookName + ", spend " + price);
        return true;
    }
 
    public void comment(String userName, String comments) {
        // 通过控制台的输出方式模拟发表书评
        System.out.println(userName + " say:" + comments);
    }
 
}

1.3对我们的目标对象进行JavaBean配置 

<!--目标对象-->
    <bean class="com.lya.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>

1.4 编写前置系统日志通知

package com.lya.aop.advice;
 
import java.lang.reflect.Method;
import java.util.Arrays;
 
import org.springframework.aop.MethodBeforeAdvice;
 
/**
 * 买书、评论前加系统日志
 * @author YU
 *
 */
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
 
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
//        在这里,可以获取到目标类的全路径及方法及方法参数,然后就可以将他们写到日志表里去
        String target = arg2.getClass().getName();
        String methodName = arg0.getName();
        String args = Arrays.toString(arg1);
        System.out.println("【前置通知:系统日志】:"+target+"."+methodName+"("+args+")被调用了");
    }
 
}

1.5配置系统通知XML中的JavaBean

<!--通知-->
    <bean class="com.lya.aop.advice.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"></bean>

1.6 配置代理XML中的JavaBean

<!-- 代理-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy">
        <!-- 配置目标对象 -->
        <property name="target" ref="bookBiz"></property>
        <!-- 配置代理接口,目标对象的接口 -->
        <property name="proxyInterfaces">
            <value>com.YU.aop.biz.IBookBiz</value>
        </property>
        <property name="interceptorNames">
            <list>
                <value>myMethodBeforeAdvice</value>
            </list>
        </property>
    </bean>

1.7 测试代码开始测试

package com.lya.util;

import com.lya.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-08-17-15:34
 */
public class Demo {
    public static void main(String[] args) {
//        今天所学:
//        1.AOP的介绍:专心做事

//       2专业术语
//        1.连接点
//        2.通知:前,后,环绕
//        3.目标
//        4.代理
//        代理=目标+通知

//        3配置xml初始化Spring容器IOC
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring.xml");

//        演示一:目标对象
//        BookBizImpl bookBiz = context.getBean("bookTarget",BookBizImpl.class);
//        bookBiz.buy("晓东","欠你一夜",2000d);
//        bookBiz.comment("晓东","不看亏了,看了真爽啊!");

//        演示二:前置通知
//        错误:类型强转,
        Object proxy1 = context.getBean("proxy");
        System.out.println(proxy1.getClass()+"代理的类型");
//      com.sun.proxy.$Proxy5代理的类型

//      这里proxy==new bookbizimpl
//        BookBizImpl proxy = context.getBean("proxy",BookBizImpl.class);
//        proxy.buy("晓东","欠你一夜",2000d);
//        proxy.comment("晓东","不看亏了,看了真爽啊!");

//        使用接口接收代理对象!!!因为代理对象实现了接口在xml中
        IBookBiz proxy = context.getBean("proxy",IBookBiz.class);
        proxy.buy("晓东","欠你一夜",2000d);
        proxy.comment("晓东","不看亏了,看了真爽啊!");

    }
}

注意这里有一个报错问题!!!

因为proxy代理已经实现了接口可以看作为一个实现类

 使用接口接收代理对象!!!因为代理对象实现了接口在xml中

测试结果:

 由测试结果可得知,不仅获取到了我们的参数,同时根据方法获取到了我们的系统日志,也就是前置通知

2. 后置通知
2.1 先准备好后置通知的系统日志

package com.zking.aop.advice;
    
import java.lang.reflect.Method;
import java.util.Arrays;
 
import org.springframework.aop.AfterReturningAdvice;
 
/**
 * 买书返利
 * @author Administrator
 *
 */
public class MyAfterReturningAdvice implements AfterReturningAdvice {
 
    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
        String target = arg3.getClass().getName();
        String methodName = arg1.getName();
        String args = Arrays.toString(arg2);
        System.out.println("【后置通知:买书返利】:"+target+"."+methodName+"("+args+")被调用了,"+"该方法被调用后的返回值为:"+arg0);
    
 
    }
 
}

2.2 配置后置系统通知的XML的JavaBean

<!--后置通知-->
    <bean class="com.YU.aop.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>
并在前面已经配置好的代理接口中添加一个value值

 2.3 测试结果

 由测试结果我们可以得知,后置通知永远都在方法执行后才会显示通知,与前置通知不同的是每次前面的方法调用后都会返回一个参数

3.环绕通知


3.1 环绕通知就是前置通知和后置通知的结合,在实际应用开发中,我们一般不会单独编写前置通知和后置通知,单独使用前置通知或者后置通知时,我们会使用环绕通知,将里面前置(后置)通知的功能注释,以达到单独使用的目的

3.2 环绕通知的系统日志

package com.lya.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.util.Arrays;

/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-08-17-18:45
 *
 * 环绕通知
 */
public class AroundAdvice  implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //获取目标对象的执行方法
        String methodName=invocation.getMethod().getName();
        //获取目标对象执行方法的参数
        Object[] params=invocation.getArguments();
        //获取目标对象
        Object target = invocation.getThis();
        System.out.println("[环绕通知] "+target.getClass().getName()+"."+methodName+","
                + "执行的参数:"+ Arrays.toString(params));

        Object returnValue = invocation.proceed(); //放行操作
        System.out.println("[环绕通知] 返回参数等于:"+returnValue);
        return returnValue;
    }
}

3.3 配置环绕通知的XML的JavaBean与前置通知和后置通知一致

3.4 测试结果

由测试结果得知,环绕通知就是前置通知和后置通知的结合,优点就是不需要再多次去进行配置及编码,所以就像我们前面所说在实际开发应用中我们一般都会选择使用环绕通知

4.异常通知
4.1 异常通知的系统日志和其他系统日志不同的是,方法名为固定的afterThrowing,不能修改

package com.lya.advice;

/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-08-17-18:56
 */

import org.springframework.aop.ThrowsAdvice;

/**
 * 异常通知
 */
public class ExceptionAdvice implements ThrowsAdvice {
        public void afterThrowing(PriceException e) {
        System.out.println("[异常通知] 价格异常,撤销订单!");
    }
}

价格异常

package com.lya.advice;

/**
 * @author 程序猿-小李哥
 * @site www.xiaolige.com
 * @company 猪八戒有限集团
 * @create 2023-08-17-19:04
 *
 * 价格异常通知
 */
public class PriceException  extends RuntimeException {
    public PriceException() {
        super();
    }
    public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
    public PriceException(String message, Throwable cause) {
        super(message, cause);
    }
    public PriceException(String message) {
        super(message);
    }
    public PriceException(Throwable cause) {
        super(cause);
    }
}

4.2 在我们正常程序出问题没有去配置异常通知时会出现报错,并且不会执行后面的后置通知,如以下情况

4.3 异常处理配置和前面的配置相同

4.4 当我们配置好异常通知模块时,程序出现异常时会上报日志进行提示

5.过滤通知
5.1 直接在XML中配置JavaBean

<!--过滤通知-->
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="regexpMethodPointcutAdvisor">
        <property name="advice" ref="myAfterReturningAdvice"></property>
        <property name="pattern" value=".*buy"></property>
    </bean>


 

将图中指出部分替换成过滤通知

 测试结果:

对比框中内容,在调用过buy方法后进行过滤,第二次调用时不再buy方法而是comment方法 

四.总结
aop是面向切面编程,普通程序由上而下正常执行,aop的程序执行是先执行到目标对象的目标方法中,如果连接点上由前置通知,则先执行前置通知再执行目标方法,最后如果目标方法有后置通知则最后执行后置通知代码,不管是前置通知,后置通知,环绕通知,异常通知,过滤通知,代码都是非业务核心代码,如日志、事务的管理(开启、提交、回滚)         
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/891197.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌在Chrome浏览器中推进抗量子加密技术

近日&#xff0c;Chromium博客上发表的一篇博文称&#xff0c;为了加强网络安全&#xff0c;应对迫在眉睫的量子计算机威胁&#xff0c;谷歌各个团队密切合作&#xff0c;为网络向抗量子密码学的过渡做好准备。 谷歌的Chrome团队在博客中写道&#xff0c;该项目涉及修订技术标准…

python3实现线性规划求解

Background 对于数学规划问题&#xff0c;有很多的实现。MatlabYALMIPCPLEX这个组合应该是比较主流的&#xff0c;尤其是在电力相关系统中占据着比较重要的地位。MATLAB是一个强大的数值计算工具&#xff0c;用于数学建模、算法开发和数据分析。Yalmip是一个MATLAB工具箱&#…

VS2022 CMake报错解决小结

目录 一、问题背景 二、问题分析 三、问题解决 一、问题背景 VS2022中能够跨平台的工程类型就是CMake项目&#xff0c;一套代码能跨windows/Linux/Mac多种操作系统。而实际使用时&#xff0c;发现相关资料比较少&#xff0c;需要摸索一下。 碰到的问题简述&#xff1a; 1、C…

VMware虚拟机Ubuntu无法连接网络的解决方法

一、解决办法 网络适配器设置 终端依次执行下面命令即可 sudo nmcli networking off sudo nmcli networking onsudo service network-manager start #或者 sudo service NetworkManager start成功出现这个图标&#xff0c;即代表网络连接成功。

Ubuntu中安装OpenSSL

文章目录 一、前期准备1.1 压缩包下载1.2 gcc, make等的安装二、安装配置 一、前期准备 1.1 压缩包下载 在安装openssl之前&#xff0c;我们需要下载对应的压缩包 https://www.openssl.org/source/openssl-3.0.1.tar.gz 此压缩包可以选择win上下载后解压再复制到本地虚拟机中…

python学习笔记——软件安装

目录 1. 安装并验证Python环境 2. 安装并设置Visual Studio Code编辑器 3. 设置Visual Studio Code编辑器 4.软件安装包 1. 安装并验证Python环境 首先&#xff0c;双击打开python安装包。 注意⚠️ &#xff1a; 安装之前需要关闭杀毒软件&#xff0c;比如360。 然后&am…

盘点九个可使用免费CDN的云服务商(2023版)

CDN的全称是Content Delivery Network&#xff0c;即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节&#xff0c;使内容传输得更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络&#x…

利用文本探测(text-detection)手写一个文本区域mask的生成

今天遇到这样一个需求&#xff1a;需要针对用户输入的图片生成对应文本区域的mask&#xff0c;按理说这应该是一个很容易实现的问题。 初步设想 要生成对应区域的mask&#xff0c;首先要找到文本所在的位置&#xff0c;针对不同的图片&#xff0c;文本位置自然是不同的&#xf…

每日一题——不同路径的数目(一)

题目 一个机器人在mn大小的地图的左上角&#xff08;起点&#xff09;。 机器人每次可以向下或向右移动。机器人要到达地图的右下角&#xff08;终点&#xff09;。 可以有多少种不同的路径从起点走到终点&#xff1f; 数据范围&#xff1a;0<n,m≤100&#xff0c;保证计算结…

129.【Spring 注解 IOC】

Spring 注解 (一)、组件注册1. Configuration 与 Bean 容器注册组件(1).无注解注入方式(2).注解注入方式 2. ComponentScan 自动扫描组件和自动扫描规则(1).无注解扫描方式(2).注解扫描注入方式(3).指定扫描或不扫描的包 (过滤) 3. 自定义TypeFilter指定过滤规则 Filter(1).自定…

宝塔端口监听不到端口

场景&#xff1a; 两个服务器同时在安装nginx 出问题导致20011没有在监听&#xff0c;重新删除nginx 就行了 当时一直以为是安全组没有放过端口&#xff0c;其实是没有监听 排查问题 php -S 0.0.0.0:端口 如果可以访问说明链接可以到服务器只是nginx没监听 sudo netstat …

Linux 发送信号

进程可以通过系统调用kill函数向包括它本身在内的其他进程发送一个信号。如果程序没有发送该信号的权限&#xff0c;对kill函数的调用就将失败&#xff0c;失败的常见原因是目标进程由另一个用户所拥有。这个函数和shell命令完成相同的功能。 一、kill函数的定义 发送信号的k…

01- 中断

中断 中断1.1 NVIC中断优先级分组1.2 外部中断<1> 映射中断线<2> 设置中断触发方式<3> 编写中断服务函数外部中断常用的库函数&#xff1a;中断函数初始化外部中断的一般配置步骤&#xff1a;部分示例&#xff1a; 中断 1.1 NVIC中断优先级分组 《stm32中文…

自动驾驶——车辆动力学模型

/*lat_controller.cpp*/ namespace apollo { namespace control {using apollo::common::ErrorCode;//故障码 using apollo::common::Status;//状态码 using apollo::common::TrajectoryPoint;//轨迹点 using apollo::common::VehicleStateProvider;//车辆状态信息 using Matri…

分模块开发的意义及开发步骤

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaweb 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Maven进阶 一、分模块开发1.1分模块开发的意义1.2分模块开…

FlexTools plugin and 3dWindow plugin for SketchUp Crack

FlexTools v2.3.6 plugin for SketchUp 3dWindow v.4.5 plugin for SketchUp 建筑师和3D艺术家使用FlexTools创建SketchUp门、窗、楼梯和其他建筑元素&#xff0c;具有卓越的速度和控制水平。 SketchUp功能强大但易于使用的扩展。对于在施工图或建筑图中使用SketchUp的每个人…

Python 学习笔记——代码基础

目录 Python基础知识 变量 赋值 数据类型 print用法 print格式化输出 运算符 if-else 数据结构 元组 in运算符 列表 切片 [ : ] 追加 append() 插入 insert&#xff08;&#xff09; 删除 pop() 字典 循环 for循环 for循环应用——遍历 for循环应用——累加…

企业如何有效进行远程控制权限管理?向日葵权限管理能力解析

企业对于远程控制这一技术的管理&#xff0c;主要分为两部分&#xff0c;一种管理的目的是提升效率&#xff0c;另一种的目的是降低风险&#xff0c;我们这里着重聊聊后者。 企业管理远控行为&#xff0c;核心关键词是“权限”&#xff0c;通过不同的权限策略和能力&#xff0…

通信模块和光模块有什么区别?通信模块是光模块吗?

在现代科技高速发展的时代&#xff0c;通信技术扮演着举足轻重的角色&#xff0c;促进着全球信息的传递与交流。而在通信技术领域&#xff0c;通信模块与光模块是两个重要的组成部分。它们都在数据传输中发挥着关键作用&#xff0c;但又有着一些显著的区别。本文易天光通信将对…

一文看尽R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD详解

一文看尽R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD详解 以下六篇文章总结详细&#xff1a; 1. 一文读懂目标检测&#xff1a;R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD 2. 【深度学习】R-CNN 论文解读及个人理解 3、R-CNN论文详解 4、一文读懂Faster RCNN 5、学一百遍都…