Spring之AOP的实现

2023-10-26

什么是AOP

AOP(Aspect Oriented Programming)意为面向切面编程,我们所熟悉的是面向对象编程(OOP),将程序中所有参与模块都抽象成对象,然后通过对象之间的相互调用关系来完成需求。

AOP 是对 OOP 的一个补充,是在另外一个维度上抽象出对象,具体是指程序运行时动态地将非业务代码切入到业务代码中,从而实现代码的解耦合,将非业务代码抽象成一个对象,对该对象进行编程这就是面向切面编程思想。

jdk动态代理实现AOP

创建一个计算器接口 Cal:

public interface Cal {
    public int add(int num1,int num2);
    public int sub(int num1,int num2);
    public int mul(int num1,int num2);
    public int div(int num1,int num2);
}

创建实现类:

public class CalImpl implements Cal {
    public int add(int num1, int num2) {
        int result = num1+num2;
        return result;
    }

    public int sub(int num1, int num2) {
        int result = num1-num2;
        return result;
    }

    public int mul(int num1, int num2) {
        int result = num1*num2;
        return result;
    }

    public int div(int num1, int num2) {
        int result = num1/num2;
        return result;
    }
}

这是一个很简单的实现简单计算的实现类,现在我们有一个需求,需要在方法计算之前打印日志记录方法信息,方法结束后再记录一次日志打印返回值等信息。

这是一个很简单的需求,我们只需要在方法前后记录日志即可,例如:

@Override
    public int add(int num1, int num2) {
        System.out.println("add方法的参数是["+num1+","+num2+"]");
        int result = num1+num2;
        System.out.println("add方法的结果是"+result);
        return result;
    }

但是对于每一个方法,都需要这样去写一下,如果方法很多,就会很麻烦,所以我们用动态代理来实现。

增加一个动态代理类:

public class MyInvocationHandler implements InvocationHandler {
    //委托对象
    private Object obj = null;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName()+"的参数是:"+ Arrays.toString(args));
        Object result = method.invoke(this.obj, args);
        System.out.println(method.getName()+"的结果是:"+result);
        return result;
    }
    //返回代理对象
    public Object bind(Object obj){
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }
}

如上代码,实现了InvocationHandler 接口,并实现了其invoke方法。简单解释一下。

bind方法中,首先将我们让类中的obj指向执行方法的原对象,因为后续代理类中的方法也是需要原对象去执行的,之后调用java中的Proxy类的近代方法去动态的生成一个代理对象。方法参数传入原对象的类加载器去加载代理类和类的所有接口去获取原对象的所有功能。

invoke,代理执行原对象的方法时,其实执行的就是这个invoke方法。我们只需要在invoke方法中去实现我们想要在方法前后所作的事,就可以了。
看下方法调用:

    public static void main(String[] args) {
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        CalImpl cal = new CalImpl();
        Cal cal2 = (Cal)myInvocationHandler.bind(new CalImpl());
        cal2.add(3,4);
    }
;

如上,我们先调用bind方法去得到jdk生成的代理类,之后调用代理类的方法,就可以实现我们想要的功能了。注意的事,这个生成的代理类其实是CalImpl的父类,所以如果CalImpl已经有父类的,是不能使用jdk动态代理的。

spring实现AOP

还是上面的原对象,下面用spring来实现AOP。

在spring中,默认就是用jdk的动态代理来实现AOP的,只是spring已经作了一些封装,我们不需要自己去实现代理类了,只需要直接使用即可。先加入依赖:

     	<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>

创建spring的xml文件。加入以下配置。

    <!-- 自动扫描 -->
    <context:component-scan base-package="com.sensen.springaop"></context:component-scan>

    <!-- 是Aspect注解生效,为目标类自动生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

之后给CalImpl加上注解@Component,交给spring管理。然后创建切面类LoggerAspect:

  @Before("execution(public int com.sensen.springaop.demo1.CalImpl.*(..))")
    public void before(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println(name+"的参数是:"+args);
    }
    @After("execution(public int com.sensen.springaop.demo1.CalImpl.*(..))")
    public void after(JoinPoint joinPoint){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法结束");
    }
    @AfterReturning(value="execution(public int com.sensen.springaop.demo1.CalImpl.*(..))",returning="result")
    public void afterReturn(JoinPoint joinPoint,Object result){
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法的结果是"+result);
    }
    @AfterThrowing(value="execution(public int com.sensen.springaop.demo1.CalImpl.*(..))",throwing="ex")
    public void afterThrowing(JoinPoint joinPoint,Exception ex){
        //获取方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name+"方法抛出异常:"+ex);
    }

如上,分别在方法执行前,执行后,返回返回值后,抛出异常后,打印了所需日志。测试一下:

		//加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //获取代理对象
        Cal proxy = (Cal) applicationContext.getBean("calImpl");
        proxy.add(10,3);
        proxy.sub(10,3);
        proxy.mul(10,3);
        proxy.div(10,3);

完成我们所需功能。

spring实现AOP默认的也是采取jdk动态代理,注意的是一般都是在对象实现接口而不是继承父类的时候,采取jdk动态代理,因为java是单继承的,而jdk生成的代理类又是原对象的父类。

当原对象是继承父类的时候,spring可以采用cglib代理方式来实现aop,只需要加上如下配置:

	<!--设置代理模式为CGlib-->
    <aop:config proxy-target-class="true"></aop:config>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring之AOP的实现 的相关文章

随机推荐

  • k8s中文件描述符与线程限制

    背景 linux中为了防止进程恶意使用资源 系统使用ulimit来限制进程的资源使用情况 包括文件描述符 线程数 内存大小等 同样地在容器化场景中 需要限制其系统资源的使用量 限制方法 ulimit docker 默认支持ulimit设置
  • 跑深度学习nvidia驱动忽然失效的详细解决方法

    由于经常跑深度学习 所以对于显卡驱动什么的都还是整的比较明白的不含糊 所以都能跑的起来 但是今天跑pytorch框架时 用到cuda 忽然给我报了个错 RuntimeError No CUDA GPUs are available 这给我整
  • 两个非递减顺序表合并成一个非递减顺序表

    两个非递减顺序表合并成一个非递减顺序表 引入 以下这个例题的描述是关于合并两个有序的数组 然后合并之后同样也是一个非递减的顺序排列 但是我名这里讲的不是顺序表 而是封装成一个顺序表 但是我们这里的顺序表其实底层同样是一个数组 所以解题的思路
  • 脚踏实地《数据结构第二章》第一节:线性表的定义和基本操作

    考点分析 一 线性表的定义 数据结构三要素 逻辑结构 定义 线性表是具有相同数据类型的n n gt 0 个数据元素的有限序列 其中n为表长 当n 0时线性表是一个空表 相同 每个数据元素所占空间一样大 帮助计算机快速找到某一个具体的元素 序
  • Deepin(Linux)下安装tensorflow-gpu(2019-5-28)

    2019 9 7更新 六 6中安装tensorflow gpu不要采用pip install tensorflow gpu 1 9 直接用conda install channel https conda anaconda org anac
  • Spring MVC案例

    文章目录 Spring MVC 基于XML配置与注解的方式使用Spring MVC 一 创建项目SpringMVCDemo01 二 在pom xml中添加依赖 三 添加项目web功能 四 创建登录页面 登录成功页面 登录失败页面 五 创建登
  • 网安之web攻防第三十天

    知识点 1 数据库堆叠注入 根据数据库类型决定是否支持多条语句执行 2 数据库二次注入 应用功能逻辑涉及上导致的先写入后组合的注入 3 数据库Dnslog注入 解决不回显 反向连接 SQL注入 命令执行 SSRF等 4 黑盒模式分析以上 二
  • airpodspro窃听模式_AirPods Pro实时收听怎么关闭? AirPods Pro实时收听的使用方法

    苹果全新AirPods Pro增加了许多新功能 首先 是控制播放 苹果在AirPods Pro中放弃了敲击手势 并用杆上的力传感器取代了它 控制音乐或视频只需要简单的短按即可 一次按压即可播放或暂停当前播放 两次按压将跳至下一曲目 而三次挤
  • 2019-07-11T09:15:41.000+0000类似时间转换

    let a 2019 07 11T09 15 41 000 0000 new Date a
  • (个人)AR电子书系统创新实训第一周(2)

    了解ZXing Net 想要在unity上实现下载资源的功能 我首先需要确认二维码扫描系统在unity上的可行性 如果要自行开发一套二维码扫描系统 不仅需要知道二维码生成和解码的原理 而且应该还需要用到一些图形学相关的代码库 如opencv
  • Android中为layout创建子文件夹

    在开发Android项目的时候 往往都有一大批java文件和layout文件 java文件分类比较简单 直接方法创建文件夹就行 但layout还需要多一步配置 看最后的文件结构图 实现步骤 1 创建相应的文件夹结构 需要注意的是 无论如何
  • ‘float‘ object has no attribute ‘decode‘

    错误代码 weibo df pd read csv Users dl Desktop 情感分析论文 词云图 微博文本数据 原始数据 原数据 表格 微博文本内容 csv print weibo df head 在读取csv或者excel文件时
  • Python基础—文件操作

    Python基础 文件操作 文件操作 文件是指为了重复使用或长期使用的目的 以文本或二进制形式存放于外部存储器 硬盘 U盘 光盘等 中的数据保存形式 文件是信息交换的重要途径 也是利用程序解决实际问题的重要媒介 程序对数据读取和处理都是在内
  • 单片机裸机环境下编写AT指令程序

    1 写在前面 AT指令在各种WIFI模块 2G 4G模块以及一些无线通讯模块中应用广泛 但是用过的朋友都知道 这种方式对于单片机编程来说 并不友好 本篇文章将以ESP8266 WIFI模块为例介绍在单片机裸机环境下编写AT指令程序的一种方式
  • 高精地图在无人驾驶中的应用

    转自 http 36kr com p 5060994 html 编者按 本文来自 程序员 作者 陈辰 刘少山 36氪经授权发布 高精地图是无人驾驶核心技术之一 精准的地图对无人车定位 导航与控制 以及安全至关重要 本文是 无人驾驶技术系列
  • PHP操作Redis LIST ,SET, HASH 的相关命令 (一)

    博客搬家 请访问 PHP操作Redis LIST SET HASH 的相关命令 一 PHP操作Redis KEY String 的相关命令 二 PHP操作Redis 有序集 Sorted Set 的相关命令 三
  • HttpServletRequest.getServletContext()一直提示找不到,而引出的问题

    开发j2ee项目的时候 需要用到servlet api 如果使用了maven web项目可以在pom xml中手动加入所需jar包 达到与依赖j2ee libarary同样的功能 可问题来了 1 问题描述 最近使用myeclipse10 7
  • 2023华为OD机试真题【打印机队列/排序】

    题目内容 有5台打印机打印文件 每台打印机有自己的待打印队列 因为打印的文件内容有轻重缓急之分 所以队列中的文件有1 10不同的代先级 其中数字越大优先级越高 打印机会从自己的待打印队列中选择优先级最高的文件来打印 如果存在两个优先级一样的
  • Struts框架(一)——简介

    引言 Struts 一个web应框架 概述 Struts基于MVC的一个web开源框架 也是一个表示层的框架 只能用于Web项目 内容 一 优缺点 1 优点 1 这是一个开源框架 能让开发人员更深入的了解其内部实现机制和原理 2 框架自带的
  • Spring之AOP的实现

    文章目录 什么是AOP jdk动态代理实现AOP spring实现AOP 什么是AOP AOP Aspect Oriented Programming 意为面向切面编程 我们所熟悉的是面向对象编程 OOP 将程序中所有参与模块都抽象成对象