SSM-Spring(三)-AOP

2023-05-16

简介

  • 什么是 AOP
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  • AOP 的作用及其优势
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
  • AOP 的底层实现
实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的
生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
  • AOP 的动态代理技术
常用的动态代理技术
JDK 代理 : 基于接口的动态代理技术
cglib 代理:基于父类的动态代理技术
  • JDK 的动态代理
①目标类接口
public interface TargetInterface {
    public void method();
}
②目标类
public class Target implements TargetInterface {
    @Override
    public void method() {
        System.out.println("Target running....");
    }
}
③动态代理代码
Target target = new Target(); //创建目标对象
//创建代理对象
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass()
.getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) 
            throws Throwable {
                System.out.println("前置增强代码...");
                Object invoke = method.invoke(target, args);
                System.out.println("后置增强代码...");
                return invoke;
            }
        }
);
④  调用代理对象的方法测试
// 测试,当调用接口的任何方法时,代理对象的代码都无序修改
proxy.method();
  • cglib 的动态代理
①目标类
public class Target {
    public void method() {
        System.out.println("Target running....");
    }
}
②动态代理代码
Target target = new Target(); //创建目标对象
Enhancer enhancer = new Enhancer();   //创建增强器
enhancer.setSuperclass(Target.class); //设置父类
enhancer.setCallback(new MethodInterceptor() { //设置回调
    @Override
    public Object intercept(Object o, Method method, Object[] objects, 
    MethodProxy methodProxy) throws Throwable {
        System.out.println("前置代码增强....");
        Object invoke = method.invoke(target, objects);
        System.out.println("后置代码增强....");
        return invoke;
    }
});
Target proxy = (Target) enhancer.create(); //创建代理对象
③调用代理对象的方法测试
//测试,当调用接口的任何方法时,代理对象的代码都无序修改
proxy.method();
  • AOP 相关概念
Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
在正式讲解 AOP 的操作之前,我们必须理解 AOP 的相关术语,常用的术语如下:
- Target(目标对象):代理的目标对象
- Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
-  Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
- Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
- Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
-  Aspect(切面):是切入点和通知(引介)的结合
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入
  • AOP 开发明确的事项
1)需要编写的内容
- 编写核心业务代码(目标类的目标方法)
- 编写切面类,切面类中有通知(增强功能方法)
- 在配置文件中,配置织入关系,即将哪些通知与哪些连接点进行结合
2)AOP 技术实现的内容
Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
3)AOP 底层使用哪种代理方式
在 spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
  • 知识要点
- aop:面向切面编程
- aop底层实现:基于JDK的动态代理 和 基于Cglib的动态代理
- aop的重点概念:
        Pointcut(切入点):被增强的方法
        Advice(通知/ 增强):封装增强业务逻辑的方法
        Aspect(切面):切点+通知
        Weaving(织入):将切点与通知结合的过程
- 开发明确事项:
        谁是切点(切点表达式配置)
        谁是通知(切面类中的增强方法)
        将切点和通知进行织入配置
  • 基于 XML 的 AOP 开发
1、快速入门
①导入 AOP 相关坐标
②创建目标接口和目标类(内部有切点)
③创建切面类(内部有增强方法)
④将目标类和切面类的对象创建权交给 spring
⑤在 applicationContext.xml 中配置织入关系
⑥测试代码
①导入 AOP 相关坐标
<!--导入spring的context坐标,context依赖aop-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.0.5.RELEASE</version>
</dependency>
<!-- aspectj的织入 -->
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.13</version>
</dependency>
②创建目标接口和目标类(内部有切点)
public interface TargetInterface {
    public void method();
}
public class Target implements TargetInterface {
    @Override
    public void method() {
        System.out.println("Target running....");
    }
}
③创建切面类(内部有增强方法)
public class MyAspect {
    //前置增强方法
    public void before(){
        System.out.println("前置代码增强.....");
    }
}
④将目标类和切面类的对象创建权交给 spring
<!--配置目标类-->
<bean id="target" class="com.demo.aop.Target"></bean>
<!--配置切面类-->
<bean id="myAspect" class="com.demo.aop.MyAspect"></bean>
⑤在 applicationContext.xml 中配置织入关系
导入aop命名空间
<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/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
⑤在 applicationContext.xml 中配置织入关系
配置切点表达式和前置增强的织入关系
<aop:config>
    <!--引用myAspect的Bean为切面对象-->
    <aop:aspect ref="myAspect">
        <!--配置Target的method方法执行时要进行myAspect的before方法前置增强-->
        <aop:before method="before" pointcut="execution(public void com.demo.aop.Target.method())"></aop:before>
    </aop:aspect>
</aop:config>
⑥测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private TargetInterface target;
    @Test
    public void test1(){
        target.method();
    }
}
⑦测试结果
前置代码增强......
Target running....

-	XML 配置 AOP 详解
1) 切点表达式的写法
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- 访问修饰符可以省略
- 返回值类型、包名、类名、方法名可以使用星号*  代表任意
- 包名与类名之间一个点 . 代表当前包下的类,两个点 .. 表示当前包及其子包下的类
- 参数列表可以使用两个点 .. 表示任意个数,任意类型的参数列表
例如:
execution(public void com.demo.aop.Target.method())	
execution(void com.demo.aop.Target.*(..))
execution(* com.demo.aop.*.*(..))
execution(* com.demo.aop..*.*(..))
execution(* *..*.*(..))
2) 通知的类型
通知的配置语法:
<aop:通知类型 method=“切面类中方法名” pointcut=“切点表达式"></aop:通知类型>
3) 切点表达式的抽取
当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽取后的切点表达式。
<aop:config>
    <!--引用myAspect的Bean为切面对象-->
    <aop:aspect ref="myAspect">
        <aop:pointcut id="myPointcut" expression="execution(* com.demo.aop.*.*(..))"/>
        <aop:before method="before" pointcut-ref="myPointcut"></aop:before>
    </aop:aspect>
</aop:config>
- 知识要点
aop织入的配置
<aop:config>
    <aop:aspect ref=“切面类”>
        <aop:before method=“通知方法名称” pointcut=“切点表达式"></aop:before>
    </aop:aspect>
</aop:config>
通知的类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知
切点表达式的写法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- 基于注解的 AOP 开发
快速入门
基于注解的aop开发步骤:

①创建目标接口和目标类(内部有切点)

②创建切面类(内部有增强方法)

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

④在切面类中使用注解配置织入关系

⑤在配置文件中开启组件扫描和 AOP 的自动代理

⑥测试
①创建目标接口和目标类(内部有切点)
public interface TargetInterface {
    public void method();
}

public class Target implements TargetInterface {
    @Override
    public void method() {
        System.out.println("Target running....");
    }
}
②创建切面类(内部有增强方法)
public class MyAspect {
    //前置增强方法
    public void before(){
        System.out.println("前置代码增强.....");
    }
}
③将目标类和切面类的对象创建权交给 spring
@Component("target")
public class Target implements TargetInterface {
    @Override
    public void method() {
        System.out.println("Target running....");
    }
}
@Component("myAspect")
public class MyAspect {
    public void before(){
        System.out.println("前置代码增强.....");
    }
}
④在切面类中使用注解配置织入关系
@Component("myAspect")
@Aspect
public class MyAspect {
    @Before("execution(* com.demo.aop.*.*(..))")
    public void before(){
        System.out.println("前置代码增强.....");
    }
}
⑤在配置文件中开启组件扫描和 AOP 的自动代理
<!--组件扫描-->
<context:component-scan base-package="com.demo.aop"/>

<!--aop的自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
⑥测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private TargetInterface target;
    @Test
    public void test1(){
        target.method();
    }
}
⑦测试结果
- 注解配置 AOP 详解
1) 注解通知的类型
通知的配置语法:@通知注解(“切点表达式")
2) 切点表达式的抽取
同 xml配置
aop 一样,我们可以将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在在增强注解中进行引用。具体如下:
@@Component("myAspect")
@Aspect
public class MyAspect {
    @Before("MyAspect.myPoint()")
    public void before(){
        System.out.println("前置代码增强.....");
    }
    @Pointcut("execution(* com.demo.aop.*.*(..))")
    public void myPoint(){}
}
  • 知识要点
    注解aop开发步骤
    ①使用@Aspect标注切面类
    ②使用@通知注解标注通知方法
    ③在配置文件中配置aop自动代理<aop:aspectj-autoproxy/>
  • 通知注解类型

参考:https://www.bilibili.com/video/BV1WZ4y1P7Bp

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SSM-Spring(三)-AOP 的相关文章

随机推荐

  • 并查集 判断无向图是否有环

    无向图中 xff0c 给定一些边 xff0c 然后判断这些边组成的图是否有环 注意这个方法必须保证没有输入重边 对于一条边用 a b 表示 xff0c 然后把a xff0c b加入到并查集中 如果又加入了一条边 b c xff0c 那么如果
  • 彻底地删除垃圾软件

    当不小心下载了垃圾软件 xff0c 想删除掉 xff0c 但是又删不掉 xff0c 或者是删不干净的一些办法 首先 xff0c 我们应该把软件关掉 xff0c 让它停止运行 然后找到软件所在的文件夹 xff0c 把一些能够删除的文件都删除掉
  • Aizu_GRL_1_c floyd算法,判断负环的题

    这题应该是很简单的 xff0c 但是我wa了好久 看了别人的博客 xff0c 还是想不明白哪有问题 xff0c 我发现别人的ac代码要判断一下 xff0c mp i k 和mp k jj 是不是等于inf xff0c 我觉得判不判断没啥区别
  • codeforces 1165D(求因子的问题)

    题意 xff1a 给出除了1和它本身之外的所有因子 xff0c 找出最小的这个数 xff0c 如果有冲突的数就输出 1 思路 xff1a 我是当时没做出来看了大佬的博客才知道 https www cnblogs com fengxunlin
  • cmd 复制文件语法不正确

    复制文件到另一个文件夹 xff1a 语法格式 xff1a copy 原文件的路径和名称 目标文件夹的路径 说语法不正确的时候可能是路径中有空格 比如C Program Files x86 CodeBlocks share CodeBlock
  • 关于斜率的计算

    codeforces 842A 从L到R中选取一个数作为分子 xff0c 从x到y中选取一个数作为分母 xff0c 给一个数k 问有没有可能这个分数等于k 这题也是有够坑的 xff0c 用二分精确的判断要超时 xff0c 但是只是看在不在范
  • c语言线性表实现电话簿(学生信息)

    c语言线性表实现电话簿 span class token macro property span class token directive keyword include span span class token string lt s
  • vsc code-runner插件运行python文件,解释器更改为ananconda

    code runner刚下载下来的默认解释器是系统自带的 xff0c 并不是anaconda的 选择文件 首选项 找到code runner executor map 找到python的命令 xff0c 改为自己的解释器位置即可
  • NT_STATUS_ACCESS_DENIED listing \*

    在centos8上配了个SAMBA与windows共享文件 访问共享目录出现 NT STATUS ACCESS DENIED listing xff0c smb gt span class token operator span span
  • RocketMQ发送普通消息的所有方法以及代码示例

    RocketMQ发送普通消息的所有方法以及代码示例 一 使用RocketMQTemplate发送消息 xff08 整合Springboot xff09 xff08 1 xff09 void send Message lt gt messag
  • C语言总结day01

    day01 1 C语言标识符 C语言标识符需满足以下条件 只能由英文字母 26个英文字母 xff0c 包括大小写即共52个 数字 0 9 和下划线组成长度为1 32必须以英文字母或下划线开头 2 C语言风格 C语言严格区分英文字母的大小写C
  • C语言总结day02

    day02 1 运算符 算术运算符 单目运算符 xff1a 43 正 xff1b 负 xff1b 双目运算符 xff1a 这三个同级 gt 43 这两个同级 注意 xff1a 前边三个的优先级大于后边的两个 xff1b 双目运算符两边运算数
  • C语言总结day03

    day03 1 数据的输入输出 数据的输出 xff1a 从计算机向输出设备 如显示器 打印机等 输出数据称为输出 数据的输入 xff1a 从输入设备 如键盘 磁盘 光盘 扫描仪等 向计算机输入数据称为输入 C语言函数库中有一批 34 标准输
  • C语言总结day04

    day04 1 int a n 是错误的 C语言中不允许对数组的大小作动态定义 2 字符数组的初始化 char a 61 I am Student char a 10 利用for语句对每个进行初始化 3 字符数组的输入和输出输入 char
  • C语言总结day06

    day06 1 定义和使用结构体变量 C语言允许用户建立由不同类型数据组成的组合型的数据结构 xff0c 它称为结构体 声明格式 struct 结构体名 成员列表 定义结构体类型变量 struct 结构体名 结构体变量 在声明类型的同时定义
  • C语言总结day07

    day07 一些概念理解 1 为什么使用指针 每一个编程语言都使用指针C 43 43 将指针暴露给了 用户 xff08 程序员 xff09 xff0c 而java和C 等语言则将指针隐蔽起来了 2 指针和引用的区别 本质 xff1a 引用是
  • C语言总结day05

    day05 1 函数间可以相互调用 xff0c 但是不能调用main函数 xff0c main函数是被操作系统调用的 2 数组作为函数参数 数组元素可以作函数参数 值传递 注意 xff1a 数组元素可以用作函数实参 xff0c 不能用作形参
  • SSM-Spring入门

    Spring学习 1 Spring简介 Spring是什么 Spring是分层的Java SE EE应用full stack轻量级开源框架 xff0c 是以loC Inverse Of Contorl 反转控制 和AOP Aspect Or
  • SSM-Spring学习(二)

    Spring IoC和DI注解开发 Spring配置数据源 数据源 xff08 连接池 xff09 介绍 xff1a 数据库连接池概念 百度百科 xff1a 数据库连接池负责分配 管理和释放数据库连接 xff0c 它允许应用程序重复使用一个
  • SSM-Spring(三)-AOP

    简介 什么是 AOP AOP 为 span class token class name Aspect span span class token class name Oriented span span class token clas