当前位置: 首页 > article >正文

Spring AOP的应用

目录

1、maven坐标配置与xml头配置

2、代理方式的选择与配置

3、AOP的三种配置方式

3.1、XML模式

3.1.1 创建目标类和方法

3.1.2 创建切面

3.1.3 切面xml配置与表达式说明

3.1.4 单测

3.2 纯注解模式

3.2.1 开启注解相关配置

3.2.2 创建目标类和方法

3.2.3 创建切面并配置切面

3.2.4 单测

3.3 XML+注解模式

3.3.1 与纯注解模式配置的区别

3.3.2 单测


AOP本质:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、⽇志代码、事务控制代码、性能监控代码。

AOP的实现,主要靠动态代理技术,在运行期对需要使用的业务逻辑方法进行增强。

1、maven坐标配置与xml头配置

<!-- Spring AOP核心包 -->

<dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-aop</artifactId>

    <version>5.1.12.RELEASE</version>

</dependency>

<!-- Spring AOP注解配置包 -->

<dependency>

    <groupId>org.aspectj</groupId>

    <artifactId>aspectjweaver</artifactId>

    <version>1.9.4</version>

</dependency>



<!--junit 单元测试依赖 -->

<dependency>

    <groupId>junit</groupId>

    <artifactId>junit</artifactId>

    <version>4.13.2</version>

    <scope>test</scope>

</dependency>

Spring基于XML的AOP配置前准备

在已经配置了ioc的xml文件上进行添加   bean.xml

<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"

       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">

2、代理方式的选择与配置

Spring 实现AOP思想使⽤的是动态代理技术。

默认情况下,Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。

当被代理对象没有实现任何接⼝时,Spring会选择CGLIB。

当被代理对象实现了接⼝,Spring会选择JDK官⽅的代理技术。

⽆论被代理对象是否实现接⼝,只要不是final修饰的类都可以采⽤cglib提供的⽅式创建代理对象。不过我们可以通过配置的⽅式,让Spring强制使⽤CGLIB。配置方式有以下两种

  • 使⽤aop:config标签配置

<aop:config proxy-target-class="true">
  • 使⽤aop:aspectj-autoproxy标签配置

<!--此标签是基于XML和注解组合配置AOP时的必备标签,表示Spring开启注解配置AOP的⽀持-->

<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

3、AOP的三种配置方式

Spring的AOP和IOC一样,支持三类配置方式:

第⼀类:使⽤XML配置

第⼆类:使⽤纯注解配置

第三类:使⽤XML+注解组合配置

3.1、XML模式

3.1.1 创建目标类和方法

public class TargetObject{

    public void printLog(String content) {

        System.out.println("printLog打印目标内容:" + content);

    }

}

3.1.2 创建切面

切面是指增强的代码,增强的代码类,就是切面类。比如:事务切面类,里面定义的方法就是事务相关的,像开启事务,提交事务,回滚事务等等。

public class LogUtil {



    public void beforeLog() {

        System.out.println("AOP切面前置通知打印");

    }



    public void afterLog() {

        System.out.println("AOP切面后置通知打印");

    }



    public void afterReturnLog() {

        System.out.println("AOP切面返回值通知打印");

    }



    public void afterThrowLog() {

        System.out.println("AOP切面异常通知打印");

    }



    public void aroundLog() {

        System.out.println("AOP切面环绕通知打印");

    }

}

3.1.3 切面xml配置与表达式说明

bean.xml

<!-- 将相关Bean注入IOC容器-->

<bean id="logUtil" class="com.test.LogUtil"/>

<bean id="targetObject" class="com.test.TargetObject"/>



<!-- 声明AOP配置 -->

<aop:config>

    <!-- 配置切入点表达式 -->

    <aop:pointcut id="cutPrintLog" expression="execution(public * com.test.TargetObject.printLog(java.lang.String))"/>

    <!-- 配置切面 -->

    <aop:aspect id="aoplog" ref="logUtil">

        <!-- 配置前置通知 -->

        <aop:before method="beforeLog" pointcut-ref="cutPrintLog"/>

        <!-- 配置后置通知 -->

        <aop:after method="afterLog" pointcut-ref="cutPrintLog"/>

        <!-- 配置返回值通知 -->

        <aop:after-returning method="afterReturnLog" pointcut-ref="cutPrintLog"/>

        <!-- 配置异常通知 -->

        <!--<aop:after-throwing method="afterThrowLog" pointcut-ref="cutPrintLog"/>-->

        <!-- 配置前置通知 -->

        <!--<aop:around method="aroundLog" pointcut-ref="cutPrintLog"/>-->

    </aop:aspect>

</aop:config>

属性说明:

method:⽤于指定通知的⽅法名称

pointcut:⽤于指定切⼊点表达式

pointcut-ref:⽤于指定切⼊点表达式的引⽤

切入点表达式使用示例

全限定⽅法名 访问修饰符 返回值 包名.包名.包名.类名.⽅法名(参数列表)

全匹配⽅式:

public void com.test.TargetObject.printLog(java.lang.String)

访问修饰符可以省略

void com.test.TargetObject.printLog(java.lang.String)

返回值可以使⽤*,表示任意返回值

* com.test.TargetObject.printLog(java.lang.String)

包名可以使⽤.表示任意包,但是有⼏级包,必须写⼏个

* ....TargetObject.printLog(java.lang.String)

包名可以使⽤..表示当前包及其⼦包

* ..TargetObject.printLog(java.lang.String)

类名和⽅法名,都可以使⽤.表示任意类,任意⽅法

* ...(java.lang.String)



参数列表,可以使⽤具体类型

基本类型直接写类型名称 : int

引⽤类型必须写全限定类名:java.lang.String

参数列表可以使⽤*,表示任意参数类型,但是必须有参数

* *..*.*(*)

参数列表可以使⽤..,表示有⽆参数均可。有参数可以是任意类型

* *..*.*(..)



全通配⽅式:

* *..*.*(..)

3.1.4 单测

@Test

public void test01() {

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

    TargetObject target = (TargetObject) context.getBean("targetObject");

    target.printLog("aaa");

}

打印结果:

AOP切面前置通知打印

printLog打印目标内容:aaa

AOP切面后置通知打印

AOP切面返回值通知打印

3.2 纯注解模式

3.2.1 开启注解相关配置

@Configuration

@ComponentScan("com.test")

// 开启注解支持

@EnableAspectJAutoProxy

public class LoggingConfig {

}

3.2.2 创建目标类和方法

@Component("targetObject")

public class TargetObject{

    public void printLog(String content) {

        System.out.println("printLog打印目标内容:" + content);

    }

}

3.2.3 创建切面并配置切面

@Component

@Aspect

public class LogUtil {



    @Pointcut("execution(* com.test.TargetObject.printLog(..))")

    public void pointcut(){}



    @Before("pointcut()")

    public void beforePrintLog(JoinPoint jp){

        Object[] args = jp.getArgs();

        System.out.println("前置通知:beforePrintLog,参数是:"+

                Arrays.toString(args));

    }

    @AfterReturning(value = "pointcut()",returning = "rtValue")

    public void afterReturningPrintLog(Object rtValue){

        System.out.println("后置通知:afterReturningPrintLog,返回值 是:"+rtValue);

    }

    @AfterThrowing(value = "pointcut()",throwing = "e")

    public void afterThrowingPrintLog(Throwable e){

        System.out.println("异常通知:afterThrowingPrintLog,异常是:"+e);

    }

    @After("pointcut()")

    public void afterPrintLog(){

        System.out.println("最终通知:afterPrintLog");

    }

    /**

     * 环绕通知

     * @param pjp

     * @return

     */

    @Around("pointcut()")

    public Object aroundPrintLog(ProceedingJoinPoint pjp){

        //定义返回值

        Object rtValue = null;

        try{

            //前置通知

            System.out.println("前置通知");

            //1.获取参数

            Object[] args = pjp.getArgs();

            //2.执⾏切⼊点⽅法

            rtValue = pjp.proceed(args);

            //后置通知

            System.out.println("后置通知");

        }catch (Throwable t){

            //异常通知

            System.out.println("异常通知");

            t.printStackTrace();

        }finally {

            //最终通知

            System.out.println("最终通知");

        }

        return rtValue;

    }

}

3.2.4 单测

@Test

public void test02() {

    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LoggingConfig.class);

    TargetObject target = (TargetObject) context.getBean("targetObject");

    target.printLog("aaa");

}

打印结果:

前置通知

前置通知:beforePrintLog,参数是:[aaa]

printLog打印目标内容:aaa

后置通知

最终通知

最终通知:afterPrintLog

后置通知:afterReturningPrintLog,返回值 是:null

3.3 XML+注解模式

3.3.1 与纯注解模式配置的区别

将 3.2.1 的LoggingConfig去掉,用xml配置;

将 3.2.2 和 3.2.3 的 @Component 去掉,用xml注入

<!-- XML中开启Spring对注解AOP的⽀持 -->
<aop:aspectj-autoproxy/>



<bean id="logUtil" class="com.test.LogUtil"/>

<bean id="targetObject" class="com.test.TargetObject"/>

3.3.2 单测

@Test

public void test01() {

    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

    TargetObject target = (TargetObject) context.getBean("targetObject");

    target.printLog("aaa");

}

打印结果:

前置通知

前置通知:beforePrintLog,参数是:[aaa]

printLog打印目标内容:aaa

后置通知

最终通知

最终通知:afterPrintLog

后置通知:afterReturningPrintLog,返回值 是:null


http://www.kler.cn/news/313747.html

相关文章:

  • 【计算机网络 - 基础问题】每日 3 题(十三)
  • 面试八股--stram 中map和flatmap的区别
  • 关于 NLP 深度学习的核心流程
  • 虚拟现实与PD协议快充
  • thinkphp 做分布式服务+读写分离+分库分表(分区)(后续接着写)
  • 【网络安全的神秘世界】攻防环境搭建及漏洞原理学习
  • LeetCode 459.重复的子字符串
  • 计算机网络分类
  • Ubuntu 22.04 源码下载、编译
  • 经典sql题(二)求连续登录最多天数用户
  • 将编程融入日常生活:编程游戏化学习
  • 内网穿透软件有哪些?
  • 搜维尔科技:工程师已经解决OptiTrack捕捉过程中肘部不自然的弯曲
  • 十五,Spring Boot 整合连接数据库(详细配置)
  • 金仓数据库 KingbaseES参考手册-(8.函数(三))
  • 在HTML中添加图片
  • Oracle 数据库常用命令与操作指南
  • 安全装备检测系统源码分享
  • 【Python报错已解决】To update, run: python.exe -m pip install --upgrade pip
  • sqlgun靶场通关攻略
  • 代码随想录算法训练营day39
  • 【C/C++语言系列】浅拷贝和深拷贝
  • php curl发送get、post请求
  • 等保测评:企业如何建立安全的开发环境
  • Opencv + Opencv_contrib的源码编译安装以及C++调用和cmakelist编写
  • 8.安卓逆向-安卓开发基础-安卓四大组件1
  • DataGrip在Windows和MacOS平台上的快捷键
  • 如何导入数据库时将ID也导入进去
  • 【推广】图书|2024新书《大模型RAG实战:RAG原理、应用与系统构建》汪鹏、谷清水、卞龙鹏等,机械工业出版社
  • 地平线占用预测 FlashOcc 参考算法-V1.0