Spring:AOP

一、AOP概念的引入

为了更好地介绍AOP,我们以登录作为示例。

首先,我们先来看一下登录的原理:

  如图所示,这是一个基本的登录原理图,但是如果我们想要在这个登录过程上再添加一些新的功能,比如权限校验,那么我们能想到的有两种方法:

  • 通过对源代码的修改来实现添加新功能
  • 不修改源代码,而是将新功能代码直接切入来实现添加新功能。即下图:

二、AOP相关概念

1、AOP的概述

(1)什么是AOP的技术?

  在软件业中,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。

  AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构。AOP最早由AOP联盟的组织提出,并制定了一套规范。Spring将AOP思想引入到框架中,就必须遵守AOP联盟的规范。

  Spring中的AOP技术是通过预编译方式或者运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

(2)为什么要学习AOP?

  因为运行期间,AOP可以在不修改源代码的情况下对已有的方法进行增强。

  利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(事务管理、安全检查、缓存)。

2. AOP的优势

  • 减少重复的代码
  • 提供开发的效率
  • 维护方便

3. AOP的底层原理

(1)JDK的动态代理技术

  JDK动态代理(必须要有接口),生成代理对象实现相同的接口,JDK动态代理底层采用接口的方式,实现增强。

  • 为接口创建代理类的字节码文件
  • 使用ClassLoader将字节码文件加载到JVM
  • 创建代理类实例对象,执行对象的目标方法

(2)cglib代理技术

  CGLIB代理技术对类生成代理对象,被代理的类是否实现接口,无所谓CGLIB底层是采用类继承的方式,实现增强。

  •   为类生成代理对象,被代理类有没有接口都无所谓,底层是生成子类,继承被代理类。

三、Spring的AOP技术--配置文件方式

1、AOP相关术语

(1)Joinpoint(连接点)

  类里面有哪些方法可以增强这些方法称为连接点。

(2)Pointcut(切入点)

  所谓切入点是指我们要对哪些Joinpoint进行拦截的定义,实际被增强的方法就是切入点。

(3)Advice(通知/增强)

  所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。通知分为前置通知、后置通知、异常通知、最终通知、环绕通知(切面要完成的功能)。

  • 前置通知:在一个方法之前执行
  • 后置通知:在一个方法执行完之后执行
  • 环绕通知:在一个方法执行之前和之后都执行
  • 异常通知:当一个方法发生异常的时候执行
  • 最终通知:类似于finally,在最后永远执行

(4)Aspect(切面)

  是一个动作,将通知应用到切入点的过程,可以理解为是切入点+通知的结合,以后自己来编写和配置的。

2、基本准备工作

  AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,AspectJ实际上是对AOP编程思想的一个实践。

3、AOP配置文件方式的入门

  创建maven项目,导入坐标依赖。

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!--AOP联盟--><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><!--Spring Aspects--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.2.RELEASE</version></dependency><!--aspectj--><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.3</version></dependency>
</dependencies>

  下面,我们以登录为例,模拟实现登录操作,来更好理解AOP的相关术语。

  这是一个Login类,其中包含实现基本登录功能的方法

public class Login {public void login(){//第一种方案,在这里添加增强功能的代码(不可行)System.out.println("登录成功......");}//现在我想在登录之前进行一次权限验证
}

  现在我们想在登录之前进行一次权限验证,两种方法:

  • 修改源代码,实现权限验证功能(这是不可行的)
  • 不修改源代码,而是采用切入的方式

  接着,我们创建切面类 ,也就是权限验证类

public class Authorization {public void anthorization(){System.out.println("进行了权限验证......");}
}

   将目标类和切面类配置到Spring中

<bean id="login" class="com.qcby.Login"></bean>
<bean id="anth" class="com.qcby.Authorization"></bean>

  在配置文件中完成AOP的配置

 <!--配置切面--><aop:config><!--配置切面 = 切入点 + 通知组成--><aop:aspect ref="anth"><!--前置通知:UserServiceImpl的save方法执行前,会增强--><!--pointcut:后边是切入点表达式,作用是知道对对面的那个方法进行增强--><aop:before method="anthorization" pointcut="execution(public void com.qcby.Login.login())"/></aop:aspect></aop:config>

  完成测试

import com.qcby.Login;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class LoginTest {@Testpublic void test(){ApplicationContext ac = new ClassPathXmlApplicationContext("Spring.xml");Login log = (Login) ac.getBean("login");log.login();}
}

  测试结果如图,我们发现在登录成功之前,的确完成了权限验证。

4、切入点的表达式

在配置切入点的时候,需要定义表达式,具体展开如下:

  切入点表达式的格式如下:

  execution([修饰符] [返回值类型] [类全路径] [方法名 ( [参数] )])

  • 修饰符可以省略不写,不是必须要出现的。
  • 返回值类型是不能省略不写的,根据你的方法来编写返回值,可以使用 * 代替。

  举例1:com.qcby.demo3.BookDaoImpl.save()

  首先包名,类名,方法名是不能省略不写的,但是可以使用 * 代替。中间的包名可以使用 * 号代替。类名也可以使用 * 号代替,也有类似的写法:*DaoImpl。方法也可以使用 * 号代替。参数如果是一个参数可以使用 * 号代替,如果想代表任意参数使用 ..,比较通用的表达式:execution(* com.qcby.*.ServiceImpl.save(..))

举例2:com.qcby.demo3.BookDaoImpl--当中所有的方法进行增强

  execution(* com.qcby.*.ServiceImpl.*(..))

举例3:com.qcby.demo3--包当中所有的方法进行增强

  execution(* com.qcby.*.*.*(..))

5、AOP的通知类型

(1)前置通知:目标方法执行前进行增强。

  如上述配置示例就是前置通知。

(2)环绕通知:目标方法执行前后,都可以进行增强。

  想要进行环绕通知,就必须要在目标对象的方法进行手动配置。

public class Authorization {public void anthorization(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{System.out.println("在方法执行之前,进行了权限验证......");proceedingJoinPoint.proceed();System.out.println("在方法执行之后,进行了权限验证......");}
}

  将上述示例中xml配置方式改为:

<aop:around method="anthorization" pointcut="execution(public void com.qcby.Login.login())"/>

  执行测试,可以发现在登录成功的前后都进行了权限验证。 

(3)最终通知:目标方法执行成功或失败,进行增强。

  将上述示例中xml配置方式改为:

<aop:after method="anthorization" pointcut="execution(public void com.qcby.Login.login())"/>

  执行测试,可以发现权限验证发生在登录成功之后。 

 (4)后置通知:目标方法执行成功后,进行增强。

  将上述示例中xml配置方式改为:

<aop:after-returning method="anthorization" pointcut="execution(public void com.qcby.Login.login())"/>

  执行测试,可以发现权限验证发生在登录成功之后。 

  后置通知和最终通知的区别:

  • 后置通知:切入点只有执行成功后才会执行。
  • 最终通知:无论我们的切入点是否成功执行都会进行通知。 

(5)异常通知:目标方法执行失败后,进行增强。(发生异常的时候才会执行,否则不执行)

  将上述示例中xml配置方式改为:

<aop:after-throwing method="anthorization" pointcut="execution(public void com.qcby.Login.login())"/>

  执行测试,可以发现仅执行了登录成功,而没有进行权限验证。 这是因为源代码中并无错误。

   此时,如果源代码出现了异常:

public class Login {public void login(){//第一种方案,在这里添加增强功能的代码(不可行)int a = 10/0;System.out.println("登录成功......");}//现在我想在登录之前进行一次权限验证
}

  那么执行结果将会进行权限验证,这就是异常通知:只有在切入点出现异常的时候才会进行通知。 

 四、Spring的AOP技术--注解方式

1、AOP注解方式入门程序

  创建maven工程,导入坐标。编写接口,完成IOC的操作。步骤略。

  编写切面类,给切面类添加注解 @Aspect,编写增强的方法,使用通知类型注解声明。

(1)配置xml扫描注解

<?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/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"><!--开启注解扫描--><context:component-scan base-package="com.aopImpl"></context:component-scan></beans>

(2) 配置注解

import org.springframework.stereotype.Component;@Component
public class Login {public void login(){System.out.println("登录成功......");}
}

  给切面类添加注解@Aspect,编写增强的方法,使用通知类型注解声明

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Component
@Aspect
public class Authorization {}

(3) 配置文件中开启自动代理

<?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/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"><!--开启注解扫描--><context:component-scan base-package="com.aopImpl"></context:component-scan><!--开启Aspect生成代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>

(4)通知类型注解

@Component
@Aspect  //生成代理对象
public class UserProxy {//增强/通知  ---》前置通知@Before(value = "execution(* com.*.User.add(..))")public void before(){System.out.println("before.............");}// 环绕通知@Around(value = "execution(* com.*.User.add(..))")public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("before.............");//  执行被增强的方法proceedingJoinPoint.proceed();System.out.println("after.............");}// 最终通知@After(value = "execution(* com.*.User.add(..))")public void after() {System.out.println("after.............");}//异常通知@AfterThrowing(value = "execution(* com.*.User.add(..))")public void afterThrowing() {System.out.println("afterThrowing.............");}//后置通知@AfterReturning(value = "execution(* com.*.User.add(..))")public void afterReturning() {System.out.println("afterReturning.............");}
}

(5) 测试类

@Test
public void aopTest1(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");user.add();
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu实时读取音乐软件的音频流

文章目录 一. 前言二. 开发环境三. 具体操作四. 实际效果 一. 前言 起因是这样的&#xff0c;我需要在Ubuntu中&#xff0c;实时读取正在播放音乐的音频流&#xff0c;然后对音频进行相关的处理。本来打算使用的PipewireHelvum的方式实现&#xff0c;好处是可以直接利用Helvum…

CUDA 学习(4)——CUDA 编程模型

CPU 和 GPU 由于结构的不同&#xff0c;具有不同的特点&#xff1a; CPU&#xff1a;擅长流程控制和逻辑处理&#xff0c;不规则数据结构&#xff0c;不可预测存储结构&#xff0c;单线程程序&#xff0c;分支密集型算法GPU&#xff1a;擅长数据并行计算&#xff0c;规则数据结…

前端会话控制技术:cookie/session/token

目录 前端中的 Cookie、Session 和 Token&#xff1a;详解与应用1. Cookie1.1 什么是 Cookie&#xff1f;1.2 Cookie 的工作原理1.3 Cookie 的特点1.4 Cookie 的用途1.5 Cookie 的安全性 2. Session2.1 什么是 Session&#xff1f;2.2 Session 的工作原理2.3 Session 的特点2.4…

MATLAB实现基于“蚁群算法”的AMR路径规划

目录 1 问题描述 2 算法理论 3 求解步骤 4 运行结果 5 代码部分 1 问题描述 移动机器人路径规划是机器人学的一个重要研究领域。它要求机器人依据某个或某些优化原则 (如最小能量消耗&#xff0c;最短行走路线&#xff0c;最短行走时间等)&#xff0c;在其工作空间中找到一…

Shopify Checkout UI Extensions

结账界面的UI扩展允许应用开发者构建自定义功能&#xff0c;商家可以在结账流程的定义点安装&#xff0c;包括产品信息、运输、支付、订单摘要和Shop Pay。 Shopify官方在去年2024年使用结账扩展取代了checkout.liquid&#xff0c;并将于2025年8月28日彻底停用checkout.liquid…

电阻的阻值识别

电阻买回来是有偏差的&#xff0c;不同的电阻种类&#xff0c;它的偏差大小会不一样&#xff0c;偏差越小的肯定越贵 主要看要求的精度要求是否越高 色环电阻或者说插件电阻 用来读数的几个色环它是比较靠近的&#xff0c;精度的色环跟用来读数的几个色环的间距会大一点点。 间…

quartz.net条件执行

quartz.net条件执行 在使用Quartz.NET时&#xff0c;你可能需要基于某些条件来决定是否执行一个任务。Quartz.NET本身并不直接支持基于条件执行任务的功能&#xff0c;但你可以通过一些策略来实现这一需求。下面是一些方法来实现基于条件的任务执行&#xff1a; 1. 使用触发器…

计算机操作系统(四) 操作系统的结构与系统调用

计算机操作系统&#xff08;四&#xff09; 操作系统的结构与系统调用 前言一、操作系统的结构1.1 简单结构1.2 模块化结构1.3 分层化结构1.4 微内核结构1.5 外核结构 二、系统调用1.1 系统调用的基本概念1.2 系统调用的类型 总结&#xff08;核心概念速记&#xff09;&#xf…

NSSCTF(MISC)——[SUCTF 2018 招新赛]single-dog

相应的做题地址&#xff1a;https://www.nssctf.cn/problem/2324 分离图片 在1.txt中得到一段颜文字 http://www.hiencode.com/aaencode.html 解密得到flag

低功耗蓝牙(BLE)方案设计实战指南

一、BLE方案设计工具链 1. 硬件选型与开发平台 TI平台&#xff1a;CC2540/CC2541芯片&#xff0c;使用SmartRF Flash Programmer烧录Nordic平台&#xff1a;nRF51822芯片&#xff0c;使用nRFgo Studio管理协议栈常用调试工具&#xff1a;TI CC Debugger、J-Link&#xff08;SW…

网络基础(一)

独立模式与网络互联 独立模式: 计算机之间相互独立。 网络互联&#xff1a;多台计算机连接在一起&#xff0c;完成数据共享。 注意&#xff1a;无论是主机内还是主机外&#xff0c;都是通过线来进行连接的&#xff0c;主机内线&#xff08;线比较短&#xff09;的连接主要考虑…

用Canvas 画布样式实现旋转的阴阳图

用Canvas 画布样式实现旋转的阴阳图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Canvas八卦图动画</title><style>/* 重置所有元素的默认样式 */* {padding: 0;margin: 0;box-sizin…

第16届蓝桥杯单片机4T模拟赛三

本次模拟赛涉及的模块&#xff1a;基础三件套&#xff08;Led&Relay&#xff0c;按键、数码管&#xff09; 进阶单件套&#xff08;pcf8591的AD模块&#xff09; 附件&#xff1a; 各模块底层代码在文章的结尾 一、数码管部分 1.页面1 页面1要显示的格式是&#xff1a; …

优选算法的睿智之林:前缀和专题(一)

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、前缀和 二、例题讲解 2.1. 一维前缀和 2.2. 二维前缀和 2.3. 寻找数组的中心下标 2.4. 除自身以外数组的乘积 一、前缀和 前缀和算法是一种用于处理数组或序列数据的算法&#xff0c;其核心思想是…

瑞萨RX23E系列开发(二)建立工程

新建工程 使用倒数第二个模板 选择路径 我这里是这个型号。根据型号选择芯片 第一次需要下载FIT

【算法day19】括号生成——数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

括号生成 https://leetcode.cn/problems/generate-parentheses/description/ 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 左括号数必须大于右括号数&#xff0c;且小于等于n class Solution { publ…

Apache Doris学习

https://doris.apache.org/zh-CN/docs/gettingStarted/what-is-apache-doris 介绍 Apache Doris 是一款基于 MPP 架构&#xff08;大规模并行处理&#xff09;的高性能、实时分析型数据库。它以高效、简单和统一的特性著称&#xff0c;能够在亚秒级的时间内返回海量数据的查询…

基于springboot的新闻推荐系统(045)

摘要 随着信息互联网购物的飞速发展&#xff0c;国内放开了自媒体的政策&#xff0c;一般企业都开始开发属于自己内容分发平台的网站。本文介绍了新闻推荐系统的开发全过程。通过分析企业对于新闻推荐系统的需求&#xff0c;创建了一个计算机管理新闻推荐系统的方案。文章介绍了…

Jboss漏洞再现

一、CVE-2015-7501 1、开环境 2、访问地址 / invoker/JMXInvokerServlet 出现了让下载的页面&#xff0c;说明有漏洞 3、下载ysoserial工具进行漏洞利用 4、在cmd运行 看到可以成功运行&#xff0c;接下来去base64编码我们反弹shell的命令 5、执行命令 java -jar ysoserial-…

(二)VMware:VMware虚拟机安装CentOS教程

目录 1、准备CentOS 7镜像1.1、官网镜像下载1.2、清华大学开源镜像下载​1.3、阿里云开源镜像下载 2、使用 VMware安装CentOS 72.1、创建虚拟机2.2、选择自定义安装2.3、硬件兼容性&#xff0c;保持默认2.4、选择下载的ISO镜像2.5、设置虚拟机名称以及存放磁盘位置2.6、按照需求…