Spring 04 -SpringAOP开发

news2024/11/23 19:43:17

SpringAOP开发

  • SpringAOP
    • 1 原理
    • 2 动态代理
      • 2.1 JDK动态代理
      • 2.2.2 Cglib动态代理
      • 2.2.3 **JDK动态代理和Cglib动态代理**
    • 3 SpringAOP
      • 3.1 AOP专业术语
      • 3.2 环境搭建
      • 3.3 基于XML配置
      • 3.4 基于注解配置
      • 2.5 通知类型

面向切面编程,在不修改源代码的情况加,对类功能实现增强


SpringAOP

1 原理

AOP原理
请添加图片描述

2 动态代理

Spring的底层技术就是动态代理

  • 动态代理分类
    • JDK动态代理
    • Cglib动态代理

2.1 JDK动态代理

接口:定义代理对象和被代理对象需要做的事情

//定义代理类和被代理类共同做的事情
public interface Subject {
    void saleHouse();
}

实现类:目标对象(被增强对象)

public class RealSubject implements Subject{
    @Override
    public void saleHouse() {
        System.out.println("买房子....");
    }
}

代理工厂

public class JDKProxyFactory {

    /**
     * 使用jdk动态代理,获取代理对象
     * @param obj   被代理对象
     * @return      代理对象
     */
    public static Object getProxy(Object obj){
        //类加载器
        ClassLoader classLoader = JDKProxyFactory.class.getClassLoader();
        //被代理对象所实现的接口
        Class<?>[] interfaces = obj.getClass().getInterfaces();
        //对对象的方法调用的拦截
        InvocationHandler invocationHandler = new InvocationHandler() {
            /**
             *
             * @param proxy             代理对象
             * @param method            拦截方法
             * @param args              拦截方法的参数
             * @return                  返回的是该方法的返回值
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //做增强工作
                System.out.println("找客户。。。。");
                Object invoke = method.invoke(obj, args);
                System.out.println("办手续。。。。");
                return invoke;
            }
        };
        Object proxyInstance = 
            Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxyInstance;
    }
}

测试

@Test
public void test01(){
    //通过代理工厂获取代理对象,通过代理对象调用方法
    Subject proxy = (Subject) JDKProxyFactory.getProxy(new RealSubject());
    proxy.saleHouse();
    //说明代理对象不属于RealSubject类,而是Subject接口的实现类
    System.out.println(proxy instanceof RealSubject); //false
}

2.2.2 Cglib动态代理

类:目标对象(被增强对象) 不需要实现接口

public class RealSubject{
    public void saleHouse() {
        System.out.println("买房子....");
    }
}

动态代理工厂

public class CglibProxyFactory {
    public static Object getProxy(Object obj){
        //创建Cglib代理工具类对象
        Enhancer enhancer = new Enhancer();
        //设置代理对象的父类(代理对象和被代理对象是继承关系)
        enhancer.setSuperclass(obj.getClass());
        Callback callback = new MethodInterceptor() {
            /**
             *
             * @param o                代理对象
             * @param method           拦截的方法
             * @param objects          拦截的方法参数
             * @param methodProxy      方法的代理对象
             * @return                 方法的返回值
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, 
                                    MethodProxy methodProxy) throws Throwable {
                
                //做增强工作
                System.out.println("找客户cglib。。。。");
                Object invoke = method.invoke(obj, objects);
                System.out.println("办手续cglib。。。。");
                return invoke;
            }
        };
        //拦截被代理对象的方法
        enhancer.setCallback(callback);
        //创建代理对象
        Object o = enhancer.create();
        return o ;
    }
}

测试

 @Test
public void test02(){
    //被代理对象
    RealSubject realSubject = new RealSubject();
    //通过代理工厂获取代理对象,通过代理对象调用方法
    //代理对象
    RealSubject proxy = (RealSubject) CglibProxyFactory.getProxy(realSubject);
    proxy.saleHouse();
    //说明代理对象属于RealSubject类,而且就是RealSubject类的子类
    System.out.println(proxy instanceof RealSubject); //true
}

2.2.3 JDK动态代理和Cglib动态代理

JDK动态代理和Cglib动态代理

  • 两者都可以实现产生代理对象
  • JDK动态代理是java原生自带的,Cglib动态代理是第三方的
  • JDK动态代理实现代理:代理对象和目标对象之间实现同一个接口
  • Cglib动态代理实现代理:代理对象是目标对象的子类

3 SpringAOP

3.1 AOP专业术语

  • 连接点(Joinpoint): 表示一切能被增强方法
  • 切入点(Pointcut): 被增强的方法 <aop:pointcut id="pc" expression="execution(* com.ying.service..*.*(..))"/>
  • 通知、增强(Advice): 增强的功能(通知的类型:前置通知、后置通知、异常通知、最终通知、环绕通知) <aop:before method="before" pointcut-ref="pc"/>
  • 目标对象(Target): 被代理对象
  • 织入(Weaving): 将通知加入连接点的过程 aop:aspect ref=""里面的代码过程
  • 代理(Proxy): 代理对象
  • 切面(Aspect): 连接点被增强的内容称之为切面(切入点+通知) aop:aspect ref=""

3.2 环境搭建

导入依赖 spring-aspects

<!-- springAOP切面开发的依赖  -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.6</version>
</dependency>

3.3 基于XML配置

aop配置文件

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.ying.aop"/>
   <!-- SpringAOP的配置   -->
    <!-- 创建增强类   -->
    <bean id="advice" class="com.ying.advice.MyAdvice"></bean>
    <aop:config>
        <!-- SpringAOP的切面   -->
        <aop:aspect ref="advice">
            <!-- SpringAOP切入点 id:切入点的唯一标识   expression:切入点表达式 -->
            <!--
                  切入点表达式
                  方法的全称
                  public void com.ying.service.impl.UserServiceImpl.addUser();
                  * com.ying.service.impl.UserServiceImpl.addUser();
                  * com.ying.service..*.*(..);
				  * com.ying.service.*.*Impl.*();
            -->
            <aop:pointcut id="pc" expression="execution(* com.ying.service..*.*(..))"/>
            <!-- SpringAOP的通知配置  -->
			<!-- <aop:before method="before" pointcut-ref="pc"></aop:before>-->
			<!-- <aop:after method="after" pointcut-ref="pc"></aop:after>-->
   			<!-- <aop:after-throwing method="throwing" pointcut-ref="pc"/>-->
			<!-- <aop:after-returning method="returning" pointcut-ref="pc"/>-->
            <aop:around method="around" pointcut-ref="pc"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>

增强(通知)类

//增强类
public class MyAdvice {
    
//    public void before(){
//        System.out.println("前置通知(在目标对象的方法之前执行)");
//    }
//    public void after(){
//        System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
//    }
//    public void throwing(){
//        System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
//    }
//    public void returning(){
//        System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
//    }
    public Object around(ProceedingJoinPoint joinPoint){
        try {
            System.out.println("前置通知(在目标对象的方法之前执行)");
            //System.out.println("方法本身");
            //执行目标对象的方法
            Object o = joinPoint.proceed();
            //获取到目标对象
            Object target = joinPoint.getTarget();
            System.out.println(target);
            //获取目标对象的方法
            Signature signature = joinPoint.getSignature();
            System.out.println(signature.getName());
            System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
            //通过调用目标对象的方法获取到返回值,并继续返回
            return o;
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
        } finally {
            System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
        }
        return null;
    }
}

测试 依赖 spring-test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest {
    @Autowired
    private UserService userService;
    @Test
    public void test01(){
        int count = userService.addUser();
        System.out.println(count);
        //userService.deleteUser();
    }
}

结果

前置通知(在目标对象的方法之前执行)
addUser...
com.ying.service.impl.UserServiceImpl@543588e6
addUser
后置通知(在目标对象的方法之后执行(如果有异常则不会执行))
最终通知(在目标对象的方法之后执行(有没有异常都会执行))
100

3.4 基于注解配置

xml配置文件

<!-- 开启注解扫描 -->
<context:component-scan base-package="com.ying"/>
<!-- 开启AOP的注解扫描   -->
<aop:aspectj-autoproxy/>

增强类

@Component
@Aspect   //设置为切面
public class MyAdvice2 {
    @Pointcut("execution(* com.ying.service..*.*(..))")
    public void pc(){}

    @Before("pc()")
    public void before(){
        System.out.println("前置通知(在目标对象的方法之前执行)");
    }
    @After("execution(* com.ying.service..*.*(..))")
    public void after(){
        System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
    }
    @AfterThrowing("execution(* com.ying.service..*.*(..))")
    public void throwing(){
        System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
    }
    @AfterReturning("execution(* com.ying.service..*.*(..))")
    public void returning(){
        System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
    }

//    @Around("execution(* com.ying.service..*.*(..))")
//    public Object around(ProceedingJoinPoint joinPoint){
//        try {
//            System.out.println("前置通知(在目标对象的方法之前执行)");
//            //System.out.println("方法本身");
//            //执行目标对象的方法
//            Object o = joinPoint.proceed();
//            //获取到目标对象
//            Object target = joinPoint.getTarget();
//            System.out.println(target);
//            //获取目标对象的方法
//            Signature signature = joinPoint.getSignature();
//            System.out.println(signature.getName());
//            System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
//            //通过调用目标对象的方法获取到返回值,并继续返回
//            return o;
//        } catch (Throwable e) {
//            e.printStackTrace();
//            System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
//        } finally {
//            System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
//        }
//        return null;
//    }
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class AOPTest {
    @Autowired
    private UserService userService;
    @Test
    public void test01(){
        userService.deleteUser();
    }
}

结果

前置通知(在目标对象的方法之前执行)
deleteUser...
后置通知(在目标对象的方法之后执行(如果有异常则不会执行))
最终通知(在目标对象的方法之后执行(有没有异常都会执行))

2.5 通知类型

  • 环绕通知
    • public Object around(ProceedingJoinPoint joinPoint){}
    • 调用目标对象的方法joinPoint.proceed();
  • 四种通知:
    • 前置通知【在调用目标方法之前执行】(开启事务)
    • 最终通知【在调用目标方法之后执行(无论是否有错都会执行)】(释放资源)
    • 异常通知【在调用目标方法报错执行】(回滚事务)
    • 后置通知【在调用目标方法之后执行】(提交事务)

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

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

相关文章

人工智能中的顶级会议

当搭建好了AI领域的知识架构&#xff0c;即具备了较好的数学、编程及专业领域知识后&#xff0c;如果想在AI领域追踪前沿研究&#xff0c;就不能再只看教材了。毕竟AI领域的发展一日千里&#xff0c;教材上的知识肯定不是最新的。此时&#xff0c;应该将关注的重点转向AI领域的…

JavaWeb - Web网站的组成,工作流程以及开发模式

一. Web Web&#xff1a;全球广域网&#xff0c;也称玩万维网(www Wrold Wide Web)&#xff0c;就是能够通过浏览器访问的网站学习Web开发&#xff0c;其实就是要使用Java这门语言来开发这样的Web网站&#xff0c;这也是现在Java语言最主流的企业级应用方式。使用Java语言开发…

Nginx基本配置 Nginx服务基础Nginx访问控制Nginx虚拟主机

本章结构 Nginx服务基础 Nginx访问控制 Nginx虚拟主机 原理&#xff1a; 关于Nginx 一款高性能、轻量级Web服务软件 稳定性高 系统资源消耗低 apache多线程或多进程实现连接&#xff08;多线程比多线程稍微好些&#xff0c;切换资源浪费少&#xff09; Nginx单线程 对HTTP并发…

自己动手写CPU——第二篇

1 ori指令说明 ori是进行逻辑 或 运算的指令&#xff0c;其指令格式如下所示 从以上的指令格式&#xff0c;我们可以直到&#xff0c;这是一个I类型指令&#xff0c;ori指令的指令码是 6‘b001101&#xff0c;所以当处理器发现正在处理的指令的高6bit 是 001101 的时候&#x…

vue3 css相关知识与动态style

scoped 当 <style> 标签带有 scoped attribute 的时候&#xff0c;它的 CSS 只会影响当前组件的元素&#xff0c;和 Shadow DOM 中的样式封装类似。 <style scoped lang"scss"> </style> 注意 &#xff1a; 作用域样式并没有消除对 class 的需求…

DN-DETR源码学习记录

DN-DETR是在DAB-DETR的基础上完成的&#xff0c;DN-DETR的作者认为导致DETR类模型收敛慢的原因在于匈牙利匹配所导致的二义性&#xff0c;即匈牙利算法匹配的离散性和模型训练的随机性&#xff0c;导致ground-truth的匹配变成了一个动态的、不稳定的过程。举个例子&#xff0c;…

字节青训营(前端)打卡day01_计网

计算机网络概论 1.前沿和课程介绍 自顶向下、自底向上 网络分层、网络协议、网络应用、HTTP123、CDN GPT. 计算机网络的发展历程可以分为四个阶段&#xff1a;单机、局域网、广域网、互联网 2.蟹堡王帝国 顾客&#xff1a;客户端 分店&#xff1a;服务端 小区转发点&…

【FFmpeg】编码器流程分析

目录1 编译2 调用关系2.1 第一帧没有获取到码流&#xff0c;第二帧获取到一帧码流2.2 送帧为NULL&#xff0c;刷新编码器获取剩余的全部码流3 总结4 感受1 编译 参考文件doc/examples/encode_video.c&#xff0c;使用x264作为编码器&#xff0c;需要先安装x264&#xff0c;编译…

如何用ChatGPT写毕业论文?

老早之前就听说有同学用ChatGPT写论文了 但是一直不觉得人工智能够真的替代人类 正好最近毕业论文开始降重了&#xff0c;超高的重复率愁得我快睡不着了 刷微博突然看到这个有关ChatGPT的问题。 出于好奇的我决定先来试试这个ChatGPT到底能不能帮我解决降重问题哈哈哈 点击…

shell脚本基础之处理脚本输入

处理输入命令行参数读取参数读取脚本名测试参数特殊参数变量参数统计获取所有参数移动变量处理选项查找选项处理简单选项分离选项和参数处理带值的选项getopt 命令命令格式在脚本中使用getoptgetopts命令脚本选项标准化获取用户的输入基本的读取超时隐藏式读取文件中读取在此之…

Linux命令·ifconfig

许多windows非常熟悉ipconfig命令行工具&#xff0c;它被用来获取网络接口配置信息并对此进行修改。Linux系统拥有一个类似的工具&#xff0c;也就是ifconfig(interfaces config)。通常需要以root身份登录或使用sudo以便在Linux机器上使用ifconfig工具。依赖于ifconfig命令中使…

OpenFeign#1 - FeignClient 是如何注册的?

文章目录EnableFeignClientsFeignClientsRegistrarregisterDefaultConfigurationregisterFeignClientsFeignClientFeignClientFactoryBeanFeignContextfeign(FeignContext)EnableFeignClients 该注解会导致 FeignClientsRegistrar 的注入. Retention(RetentionPolicy.RUNTIME…

Redis AOF

一、Redis AOF 1.简介 目前&#xff0c;redis的持久化主要应用AOF(Append Only File)和RDB两大机制。AOF以日志的形式来记录每个写操作(增量保存),将redis执行过的所有写指令全部记录下来(读操作不记录)。只许追加文件&#xff0c;但不可以改写文件。redis启动之初会读取该文…

自动化测试学习(七)-正则表达式,你真的会用吗?

目录 一、正则表达式在python中如何使用 二、用正则表达式匹配更多模式 三、常用字符分类的缩写代码 总结 所谓正则表达式&#xff08;regex&#xff09;&#xff0c;就是一种模式匹配&#xff0c;学会用正则匹配&#xff0c;就可以达到事半功倍的效果。 一、正则表达式在…

工程管理系统软件 自主研发,工程行业适用

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示…

在 Web3 里如何寻找靠谱的创新路径——Solv V3 阶段性复盘(上)

作者&#xff1a;Solv 核心团队Solv V3 是 3 月 21 日发布的&#xff0c;到这周一整整三个星期。三周时间产生的实际交易额超过 6,000 万美元&#xff0c;预计在本月内能够破亿。而且从我们手上的 pipeline 来看&#xff0c;这个增长的势头还将持续下去。在几个月内&#xff0c…

「Long HK, Long Crypto」主题酒会在香港圆满举行!Web3er齐聚一堂共叙行业发展

「2023 香港 Web3 嘉年华」是香港有史以来规模最大的加密货币活动之一&#xff0c;邀请了300多位行业领袖、区块链项目创始人、投资人、监管机构代表、专家学者&#xff0c;为每一位参与者带来前沿的 Web3 技术&#xff0c;共同探讨 Web3 未来发展的关键问题。 Web3相关的各大…

OpenCV实战(19)——特征描述符

OpenCV实战&#xff08;19&#xff09;——特征描述符0. 前言1. 特征描述符2. 提升匹配集质量2.1 交叉检查匹配2.2 比率测试2.3 距离阈值3. 完整代码小结系列链接0. 前言 SURF 和 SIFT 关键点检测算法为每个检测到的特征计算位置、方向和比例&#xff0c;比例因子信息可用于定…

RestClient查询文档

文章目录1、RestClient查询文档----快速入门2、查询文档--match、term、range、bool3、查询文档-排序和分页4、高亮1、RestClient查询文档----快速入门 基本步骤 1.先创建SearchRequest对象&#xff0c;调用source方法&#xff08;DSL&#xff09;——>相当于红框内的大jso…

最前端|什么是低代码?与传统开发的区别是什么?

目录一、低代码介绍二、背景趋势三、低代码与传统代码开发&#xff08;一&#xff09;低代码能否替代传统开发低代码页面传统开发页面&#xff08;二&#xff09;相同业务不同方式对比1.低代码开发&#xff08;1&#xff09;优点&#xff08;2&#xff09;缺点2.传统代码开发&a…