SpringAOP入门案例

2023-09-20 11:02:17

在这里插入图片描述

package com.elf.spring.aop.aspectj;
/**
 * @author 45
 * @version 1.0
 */
public interface UsbInterface {
    public void work();
}

package com.elf.spring.aop.aspectj;
import org.springframework.stereotype.Component;
/**
 * @author 45
 * @version 1.0
 */
@Component //把Phone对象当做一个组件注入容器
public class Phone implements UsbInterface{
    @Override
    public void work() {
        System.out.println("手机开始工作了....");
    }
}

package com.elf.spring.aop.aspectj;
import org.springframework.stereotype.Component;
/**
 * @author 45
 * @version 1.0
 */
@Component //将Camera注入到spring容器
public class Camera implements UsbInterface {
    @Override
    public void work() {
        System.out.println("相机开始工作...");
    }
}
package com.elf.spring.aop.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author 45
 * @version 1.0
 * 切面类 , 类似于我们以前自己写的MyProxyProvider,但是功能强大很多
 *
 */
@Order(value = 2)//表示该切面类执行的顺序, value的值越小, 优先级越高
@Aspect //表示是一个切面类[底层切面编程的支撑(动态代理+反射+动态绑定...)]
@Component //会注入SmartAnimalAspect到容器
public class SmartAnimalAspect {


    //定义一个切入点, 在后面使用时可以直接引用, 提高了复用性
    @Pointcut(value = "execution(public float com.elf.spring.aop.aspectj.SmartDog.getSum(float, float)))")
    public void myPointCut() {
    }

    //希望将f1方法切入到SmartDog-getSum前执行-前置通知

    /**
     * 解读
     * 1. @Before 表示前置通知:即在我们的目标对象执行方法前执行
     * 2. value = "execution(public float com.elf.spring.aop.aspectj.SmartDog.getSum(float, float)
     * 指定切入到哪个类的哪个方法  形式是: 访问修饰符 返回类型 全类名.方法名(形参列表),
     *     带形参列表是因为方法名可能相同,参数个数不同构成重载,以便区分.
     * 3. showBeginLog方法可以理解成就是一个切入方法, 这个方法名是可以程序员指定  比如:showBeginLog
     * 4. JoinPoint joinPoint 在底层执行时,由AspectJ切面框架, 会给该切入方法传入 joinPoint对象
     * , 通过该方法,程序员可以获取到 相关信息
     *
     * @param joinPoint
     */
    //@Before(value = "execution(public float com.elf.spring.aop.aspectj.SmartDog.getSum(float, float))")
    //这里我们使用定义好的切入点
    @Before(value = "myPointCut()")
    //如果说是一个切入方法,那么形参是JoinPoint joinPoint,用aop来做的开发主要是由aspectj框架来支撑的
    public void showBeginLog(JoinPoint joinPoint) {
        //通过连接点对象joinPoint 可以获取方法签名
        Signature signature = joinPoint.getSignature();
        //signature.getName()方法签名指的是:com.elf.spring.aop.aspectj.SmartDog.getSum
        System.out.println("SmartAnimalAspect-切面类showBeginLog()[使用的myPointCut()]-方法执行前-日志-方法名-" + signature.getName() + "-参数 "
                + Arrays.asList(joinPoint.getArgs()));//(float, float)
    }

    //返回通知:即把showSuccessEndLog方法切入到目标对象方法正常执行完毕后的地方
    //老韩解读
    //1. 如果我们希望把目标方法执行的结果,返回给切入方法
    //2. 可以再 @AfterReturning 增加属性 , 比如 returning = "res"
    //3. 同时在切入方法增加 Object res
    //4. 注意: returning = "res" 和 Object res 的 res名字一致
    //@AfterReturning(value = "execution(public float com.elf.spring.aop.aspectj.SmartDog.getSum(float, float))", returning = "res")
    //使用切入点
    @AfterReturning(value = "myPointCut()", returning = "res")
    public void showSuccessEndLog(JoinPoint joinPoint, Object res) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() + " 返回的结果是=" + res);
    }


    //异常通知:即把showExceptionLog方法切入到目标对象方法执行发生异常的的catch{}
    //@AfterThrowing(value = "execution(public float com.elf.spring.aop.aspectj.SmartDog.getSum(float, float))", throwing = "throwable")
    //直接使用切入点表达式
    @AfterThrowing(value = "myPointCut()", throwing = "throwable")
    public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName() + " 异常信息=" + throwable);
    }

    //最终通知:即把showFinallyEndLog方法切入到目标方法执行后(不管是否发生异常,都要执行 finally{})
    //@After(value = "execution(public float com.elf.spring.aop.aspectj.SmartDog.getSum(float, float))")
    //直接使用切入点
    @After(value = "myPointCut()")
    public void showFinallyEndLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-" + signature.getName());
    }

    //新的前置通知
    //@Before(value = "execution(public void com.elf.spring.aop.aspectj.Phone.work()) || execution(public void com.elf.spring.aop.aspectj.Camera.work())")
    //public void hi(JoinPoint joinPoint) {
    //    Signature signature = joinPoint.getSignature();
    //    System.out.println("切面类的hi()-执行的目标方法-" + signature.getName());
    //}

    //切入表达式也可以指向接口的方法, 这时切入表达式会对实现了接口的类/对象生效
    //比如下面我们是对UsbInterface 切入,那么对实现类Phone 和 Camera对象都作用了
    @Before(value = "execution(public void com.elf.spring.aop.aspectj.UsbInterface.work())")
    public void hi(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("切面类的hi()-执行的目标方法-" + signature.getName());
    }


    //给Car配置一个前置通知,即将ok1()方法切入到Car类的run()方法前
    @Before(value = "execution(public void Car.run())")
    public void ok1(JoinPoint joinPoint) {

        Signature signature = joinPoint.getSignature();
        System.out.println("切面类的ok1()-执行的目标方法-" + signature.getName());

    }

    //返回通知
    @AfterReturning(value = "execution(public void Car.run())")
    public void ok2(JoinPoint joinPoint) {

        Signature signature = joinPoint.getSignature();
        System.out.println("切面类的ok2()-执行的目标方法-" + signature.getName());

    }

    //异常通知
    @AfterThrowing(value = "execution(public void Car.run())")
    public void ok3(JoinPoint joinPoint) {

        Signature signature = joinPoint.getSignature();
        System.out.println("切面类的ok3()-执行的目标方法-" + signature.getName());

    }

    //后置通知
    @After(value = "execution(public void Car.run())")
    public void ok4(JoinPoint joinPoint) {


        Signature signature = joinPoint.getSignature();
        System.out.println("切面类的ok4()-执行的目标方法-" + signature.getName());
        //演示一下JoinPoint常用的方法.
        joinPoint.getSignature().getName(); // 获取目标方法名
        joinPoint.getSignature().getDeclaringType().getSimpleName(); // 获取目标方法所属类的简单类名
        joinPoint.getSignature().getDeclaringTypeName(); // 获取目标方法所属类的类名
        joinPoint.getSignature().getModifiers(); // 获取目标方法声明类型(public、private、protected)
        Object[] args = joinPoint.getArgs(); // 获取传入目标方法的参数,返回一个数组
        joinPoint.getTarget(); // 获取被代理的对象
        joinPoint.getThis(); // 获取代理对象自己
    }
}

package com.elf.spring.aop.aspectj;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 45
 * @version 1.0
 */
public class AopAspectjTest {

    @Test
    public void smartDogTestByProxy() {

        //得到spring容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans08.xml");
        //这里我们需要通过接口类型来获取到注入的SmartDog对象-就是代理对象
        SmartAnimalable smartAnimalable =
                ioc.getBean(SmartAnimalable.class);

        //SmartAnimalable smartAnimalable =
        //        (SmartAnimalable)ioc.getBean("smartDog");

        smartAnimalable.getSum(10, 2);

        System.out.println("smartAnimalable运行类型="
                + smartAnimalable.getClass());

        System.out.println("=============================");

        //smartAnimalable.getSub(100, 20);

    }

    @Test
    public void smartDogTestByProxy2() {

        //得到spring容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans08.xml");

        UsbInterface phone = (UsbInterface) ioc.getBean("phone");
        UsbInterface camera = (UsbInterface) ioc.getBean("camera");

        phone.work();

        System.out.println("==================");

        camera.work();

    }

    @Test
    public void test3() {
        //得到spring容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans08.xml");

        Car car = ioc.getBean(Car.class);

        //说明: car对象仍然是代理对象
        System.out.println("car的运行类型=" + car.getClass());

        car.run();

    }

    @Test
    public void testDoAround() {
        //得到spring容器
        ApplicationContext ioc =
                new ClassPathXmlApplicationContext("beans08.xml");


        SmartAnimalable smartAnimalable =
                ioc.getBean(SmartAnimalable.class);

        smartAnimalable.getSum(10, 2);
    }

}

更多推荐

以小见大,彻底理解 cookie,session,token 之间的关系,通俗易懂

发展史1、很久很久以前,Web基本上就是文档的浏览而已,既然是浏览,作为服务器,不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP协议,就是请求加响应,尤其是我不用记住是谁刚刚发了HTTP请求,每个请求对我来说都是全新的。这段时间很嗨皮2、但是随着交互式Web应用的兴起,像在线购物网站,需要登录的

Java关于AbstractProcessor的使用

文章目录Step1项目准备Step2开发一个自定义的AbstractProcessorStep3DebugAbstractProcessor替换源码内容运行SpringBoot应用测试源码内容是否成功替换背景:我们都知道,在正常情况下,我们无法去变更二方,三方包中源码的Java文件的内容,但是在某些场景下,我们又希望可

Android Jetpack Compose之状态持久化与恢复

目录1.概述2.实例解析4.Compose提供的MapSaver和ListSaver4.1mapServer4.2ListSaver1.概述在之前的文章中,我们提到了remember,我们都知道remember可以缓存创建状态,避免因为重组而丢失。使用remember缓存的状态虽然可以跨越重组,但是不能跨Activit

热门免费api接口:含物流api,短信api,天气api等

热门免费api接口:含物流api,短信api,天气api。。。全国快递物流查询:目前已支持600+快递公司的快递信息查询。自动识别快递公司及单号,服务器毫秒响应,数据及时准确。通知短信:短信通知支持三大运营商以及虚拟运营商。短信验证码:支持三大运营商,支持大容量高并发。语音验证码短信:拨打电话告知用户验证码,实现信息验

【C++】动态内存管理 ③ ( C++ 对象的动态创建和释放 | new 运算符 为类对象 分配内存 | delete 运算符 释放对象内存 )

文章目录一、C++对象的动态创建和释放1、C语言对象的动态创建和释放的方式2、C++语言对象的动态创建和释放的方式二、代码示例-对象的动态创建和释放一、C++对象的动态创建和释放使用C语言中的malloc函数可以为类对象分配内存;使用free函数可以释放上述分配的内存;使用C++语言中的new运算符也可以为类对象分配内

【C++】动态内存管理 ② ( new 运算符 为 基础数据类型 / 基础数据数组类型 分配堆内存 )

文章目录一、C++对象的动态创建和释放二、new运算符为基础数据类型/基础数据数组类型分配堆内存1、语法说明2、语法简单示例3、代码示例-基础类型内存分配4、代码示例-基础数组类型内存分配三、完整代码示例-new运算符为基础数据类型/基础数据数组类型分配堆内存一、C++对象的动态创建和释放动态内存管理在C++语言中,就

浅谈C++|多态篇

1.多态的基本概念多态是C++面向对象三大特性之一多态分为两类1.静态多态:函数重载和运算符重载属于静态多态,复用函数名·2.动态多态:派生类和虚函数实现运行时多态静态多态和动态多态区别:·静态多态的函数地址早绑定–编译阶段确定函数地址·动态多态的函数地址晚绑定–运行阶段确定函数地址下面通过案例进行讲解多态动态多态满足

MySQL之优化SELECT语句

MySQL之优化SELECT语句文章目录MySQL之优化SELECT语句摘要:引言:1.MySQL性能提成优化概述2.WHERE子句优化3.范围优化4.哈希联接优化5.储存引擎下的优化6.索引条件下推优化7.嵌套循环联接算法8.嵌套联接优化(JOIN)总结:摘要:本文主题为MySQL优化SELECT语句,涵盖了数据库性

MySQL什么情况下会死锁,发生了死锁怎么处理呢?

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。🏆本文已收录于PHP专栏:MySQL的100个知识点。🎉欢迎👍点赞✍评论⭐收藏文章目录🚀一、前言-关于数据

数据库 MVCC 详解

目录1.什么是MVCC?2.MVCC的好处?3.快照读?当前读分别是什么?怎么理解?3.1快照读3.2当前读4.MVCC实现原理4.1隐藏字段4.2undolog(版本链)4.3readView5.readView深层详解6.数据库的四种隔离级别7.读已提交和可重复读的区别?7.1MVCC主要作用体现在读已提交和可重复

【Rust 基础篇】Rust 非对象安全

导言在Rust中,Trait是一种用于实现共享行为和抽象的重要特性。然而,并非所有的Trait都是对象安全的。当Trait不满足对象安全的条件时,就被称为非对象安全的Trait。本篇博客将深入探讨Rust中的非对象安全问题,解释什么是非对象安全,为什么会出现这种情况,以及如何处理和避免非对象安全的问题。让我们开始吧!什

热文推荐