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

Spring AOP快速入门----XML方式和注解方式

一、AOP概念(面向切面编程)

1. AOP优点是在不修改源码的情况下,对方法进行增强,使得代码易于维护,提高了开发效率。

2. Spring的AOP底层原理的是动态代理方式(jdk和cglib两种常用动态代理方式),通过Spring的封装,只需要对Spring核心配置文件applicationContext.xml文件进行相应配置即可实现AOP。


二、AOP相关术语

  • Target(目标对象):代理的目标对象;
  • Proxy(代理对象):目标对象被AOP织入增强后,产生的结果类;
  • JoinPoint(连接点):可以被AOP织入增强的点(方法);
  • Pointcut(切入点):从连接点中选取,进行AOP织入增强的点(方法);
  • Advice(通知/增强):对连接点(方法)进行的增强操作;
  • Aspect(切面):切点+通知;
  • Weaving(织入):对切入点进行增强,并创建代理对象的过程;

三、AOP开发过程

1. 编写核心业务代码:目标类的目标方法;

2. 编写切面类,并在切面类中编写增强方法(通知);

3. 在applicationContext.xml中配置织入关系:将增强方法对应到连接点;

注1: 通过Spring框架监控切入点的方法的执行,使用代理机制,动态创建目标对象的代理对象,根据增强方法的类别(before,after,around…),在代理对象的对应位置,将增强方法织入。】
注2: 在Spring中,框架会根据目标类是否有接口来决定采用哪种代理方式】

四、基于XML的AOP开发

1. 在pom.xml中导入需要的坐标;

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>SpringAOP</groupId>
  <artifactId>SpringAOP</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.18</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.4</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
    </dependency>

  </dependencies>

</project>

2.创建目标接口,目标类,目标方法;

package com.aop;

public interface TargetInterface {
    void save();
}
package com.aop;

public class Target implements TargetInterface {
    public void save() {
        System.out.println("<<目标方法执行...>>");
    }
}

3. 创建切面类和增强方法;

package com.aop;

public class Aspect {
    public void beforeMethod(){
        System.out.println("<<前置增强方法...>>");
    }

    public void afterReturningMethod(){
        System.out.println("<<后置增强方法...>>");
    }
    
}

4. 配置织入关系;

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

                               ">

    <!--目标对象-->
    <bean id="target" class="com.aop.Target"></bean>

    <!--切面对象-->
    <bean id="aspect" class="com.aop.Aspect"></bean>

    <!--配置织入-告诉spring框架,哪些方法(切点)需要进行哪些增强-->
    <aop:config>
        <!--声明切面-->
        <aop:aspect ref="aspect">
        <!--抽取切点表达式-->
            <!--<aop:pointcut id="pointCut" expression="execution(public void com.aop.Target.save())"></aop:pointcut>-->          
            <aop:before method="beforeMethod" pointcut="execution(public void com.aop.Target.save())"></aop:before>
            <aop:after method="afterReturningMethod" pointcut="execution(public void com.aop.Target.save())"></aop:after>
        </aop:aspect>
    </aop:config>

</beans>

  • 切点表达式语法:execution(修饰符 返回值类型 包名.类名.方法名(参数))

    • 访问修饰符可以省略;
    • 返回值类型,包名,类名,方法名可以使用 * 替代,代表 :任意;
    • 包名和类名之间一个 . 代表当前包下的类,两个 . 代表当前包及其子包下的类;
    • 参数列表使用两个 . 表示任意类型的参数列表;
    • execution(public void com.aop.Target.save());
    • execution(* com . aop . *. * ( . . ));
    • execution(* com . aop . . * . * (. .));

  • 增强(通知)类型:<aop:通知类型 method=“切面类中增强方法名” pointcut=“切点表达式”></aop:通知类型>

名称标签说明
前置通知< aop:before />指定增强方法在切入点之前执行
后置通知< aop:after-returning />指定增强方法在切入点之后执行
环绕通知< aop:around />指定增强方法在切入点之前和之后都执行
异常抛出通知< aop:throwing />指定增强方法在目标方法出现异常时执行
最终通知< aop:after />无论目标方法是否出现异常,都执行
  • 切点表达式抽取:不同的通知类型对应同一切点表达式时,可对表达式进行抽取;
 <aop:pointcut id="pointCut" expression="execution(public void com.aop.Target.save())"></aop:pointcut>-->

5. 测试与结果

package test;
import com.aop.TargetInterface;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {
    @Test
    public void test1(){
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        //使用TargetInterface 说明被增强后的对象即(proxy对象)和原来的target对象是兄弟关系,所以用父类接口实现
        TargetInterface target = (TargetInterface) app.getBean("target");
        target.save();
    }
}

在这里插入图片描述

四、基于注解的AOP开发

1. 创建目标接口,目标类,目标方法(上同);

2. 创建切面类和增强方法(上同);

3. 将目标类和切面类的对象创建权交给spring;

package com.aop;

import org.springframework.stereotype.Component;

@Component("target") //由spring产生bean对象
public class Target implements TargetInterface {
    public void save() {
        System.out.println("<<目标方法执行...>>");
    }
}

在这里插入图片描述

4. 在切面类中使用注解配置织入关系;

package com.aop;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component("aspect")
@org.aspectj.lang.annotation.Aspect //标注当前类是切面类
public class Aspect {

    // 配置前置通知
    @Before(value = "execution(void com.aop.Target.save())")
    public void beforeMethod(){
        System.out.println("<<前置增强方法...>>");
    }

    // 配置后置通知
    @AfterReturning(value = "pointcut()")
    public void afterReturningMethod(){
        System.out.println("<<后置增强方法...>>");
    }
    
    // 定义切点表达式方法,用于抽取
    @Pointcut("execution(void com.aop.Target.save())")
    public void pointcut(){
    }
}

  • 增强(通知)类型:@通知类型(value = “切点表达式”)
名称标签说明
前置通知@Befoe指定增强方法在切入点之前执行
后置通知@AfterReturning指定增强方法在切入点之后执行
环绕通知@Around指定增强方法在切入点之前和之后都执行
异常抛出通知@AfterThrowing指定增强方法在目标方法出现异常时执行
最终通知@After无论目标方法是否出现异常,都执行

5. 在配置文件中开启组件扫描和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:context="http://www.springframework.org/schema/context"
       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 http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd
                               ">
    <!--组件扫描-->
    <context:component-scan base-package="com.aop"></context:component-scan>

    <!--AOP自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

6. 测试与结果;

package test;
import com.aop.TargetInterface;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {
    @Test
    public void test1(){
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        //使用TargetInterface 说明被增强后的对象即(proxy对象)和原来的target对象是兄弟关系,所以用父类接口实现
        TargetInterface target = (TargetInterface) app.getBean("target");
        target.save();
    }
}

在这里插入图片描述

相关文章:

  • 读源码学算法之Octree color quantization
  • C#调用C++生成的DLL 找不到入口点 以及 尝试读取或写入受保护的内存
  • 品牌是选择KOC还是KOL?抖音KOC如何进行推广投放?
  • css同时设置最大宽度和最小宽度
  • 微信小程序播放视频的时候如果突然插入一个音频视频就会卡顿一下
  • S7协议下,如何搭建触摸屏与PLC之间无线通信?
  • java SpringBoot 静态方法中获取@Value注入的值
  • 以太坊账户私钥管理之导出、导出keystore 文件
  • byte[] 转换为图片并保存
  • opencv中直方图和颜色跟踪相关:calcHist, calcBackProject, Meanshift和Camshift
  • 敏感词过滤实践
  • 【面试题】公平锁和非公平锁/可重入锁
  • 【字体转换】快速实现繁简字体相互转换
  • Jeecg Online代码生成器--单表代码生成
  • 获取一个实时走动的时间
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • angular2开源库收集
  • Java 多线程编程之:notify 和 wait 用法
  • JavaScript 一些 DOM 的知识点
  • JAVA并发编程--1.基础概念
  • node学习系列之简单文件上传
  • tab.js分享及浏览器兼容性问题汇总
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • 创建一个Struts2项目maven 方式
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 世界上最简单的无等待算法(getAndIncrement)
  • 详解移动APP与web APP的区别
  • 一个SAP顾问在美国的这些年
  • 最近的计划
  • const的用法,特别是用在函数前面与后面的区别
  • Spring第一个helloWorld
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​ssh免密码登录设置及问题总结
  • # 数据结构
  • #stm32驱动外设模块总结w5500模块
  • (超详细)语音信号处理之特征提取
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (二)正点原子I.MX6ULL u-boot移植
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (算法二)滑动窗口
  • (转)Linq学习笔记
  • *setTimeout实现text输入在用户停顿时才调用事件!*
  • ./configure,make,make install的作用
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .NET gRPC 和RESTful简单对比
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .Net接口调试与案例
  • .Net小白的大学四年,内含面经
  • /proc/stat文件详解(翻译)
  • /usr/bin/env: node: No such file or directory
  • @selector(..)警告提示
  • @Valid和@NotNull字段校验使用
  • [2023年]-hadoop面试真题(一)
  • [30期] 我的学习方法