什么是面向切面编程

先大概了解一下部分术语

横切关注点:软件开发中,散布于多出的功能称为横切关注点(cross-cutting concern),简单的可以描述为可以影响应用多处的功能,比如日志、安全。

切面:切面能帮我们模块化横切关注点,如图所示,三个不同的模块,每个模块都是为特定业务服务,但是这些模块都需要类似的辅助功能,例如安全、事务管理。面向切面,可以使我们在一个地方定义通用功能,以声明的方式定义这个功能要以何种方式在何处使用,无需修改受影响的类,横切关注点可以被模块化为一个特殊的类,这些类被称为切面。

AOP带来的好处:

  1、每个关注点集中于一个地方,而不是分散到多处代码。

  2、服务模块更简洁,因为它们只包含主要关注点(或核心功能)的代码,次要关注点的代码被转移到切面中了。

AOP术语

常见术语:通知(advice)、切点(pointcut)、连接点(point)

1、通知(advice):切面的所做的工作被称为通知(什么时候做)

  通知定义了切面是什么以及何时使用,描述切面要完成的工作和何时执行这个工作。

  Spring切面可以应用5种类型的通知:

  1、前置通知(Before):在目标方法被调用之前调用通知;

  2、后置通知(After):在目标方法被调用之后调用通知;

  3、返回通知(After-returning):在目标方法成功执行之后调用通知;

  4、异常通知(After-throwing):在目标方法抛出异常后调用通知;

  5、环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义行为。

2、连接点(Join point):插入切面的时机,在应用执行“过程中”能够插入切面的一个点(做的时机)

  应用可能有无数的时机应用通知,这些时机被称为连接点。这个点可以使调用方法时,抛出异常时,甚至是修改一个字段时,切面代码可以利用这些连接点插入到应用的正常流程中。

3、切点(Poincut):插入切面的位置(在什么地方做)

  明确要织入的一个或多个连接点,通常使用明确的类和方法名称,或正则表达式匹配类和方法名,来指定切点。

4、切面(Aspect):通知和切点的结合。(在什么时候什么地方做)

  通知和切点共同定义了切面的全部内容-----它是什么,在什么时候何处完成其功能。

5、引入(Introduction):不修改仙有泪的情况下,向现有类引入新功能

  引入允许我们向现有类添加新方法或属性。

6、织入(Weaving):把切面应用到目标对象,并创建新的代理对象的过程。

  切面在指定的连接点被织入到目标对象中,在目标对象的生命周期中有多个点可织入:

  1、编译期:切面在目标类编译时被织入,这种方式需要特殊的编译器,AspectJ的织入编译器就是以这种方式织入。

  2、类加载期:切面在目标类加载到JVM中被织入,此方式需要特殊的类加载器(ClassLoader),其可以在目标类被引入应用之前增强该类的字节码。AspectJ 5的加载时织入(LTW)就是这种方式织入的。

  3、运行期:切面在应用运行时的某个时刻被织入,一般情况下,织入切面时,AOP容器会为目标对象动态的创建一个代理对象,Spring AOP就是以这种方式织入的。

通过切点来选择连接点

Spring AOP中可以使用AspectJ切点表达式语言定义切点,如下为Spring AOP所支持的AspectJ切点指示器:

编写切点

首先写一个接口用于演示如何定义切点,如下接口可以代表任何类型的现场表演,如舞台剧、电影等。

  1. public interface Performance {
  2. public void perform();
  3. }

假设我们向编写上面接口的perform()方法触发通知,如下展示了一个接口表达式

execution()指示器选择Performance的perform方法,方法表达式以“ * ” 号开始,表示我们不关心方法的返回值类型,可以理解为一个通配符。

*号之后指定了全限定的类名和方法名,对于方法的参数列表使用2个点好(..)表示切点选择任意参数签名的perform()方法。

现在加入我们需要配置的切点仅匹配concert包,可使用within()指示器来限制匹配,如下图。

使用“&&”操作符连接execution()和within()指示器,形成“与”(AND)的关系,(也可以使用||(或)、!(非)标识操作,也可以使用and、or、not来代替)

在切点中选择bean

除了表4.1所列的指示器外,Spring还引入了一个新的bean()指示器,它允许我们在切点表达式中使用bean的ID来标识bean。bean()使用bean ID或bean名称作为参数来限制切点只匹配特定的bean。例如,考虑如下的切点:在这里,我们希望在执行Performance的perform()方法时应用通知,但限定bean的ID为woodstock。在某些场景下,限定切点为指定的bean或许很有意义,但我们还可以使用非操作为除了特定ID以外的其他bean应用通知:在此场景下,切面的通知会被编织到所有ID不为woodstock的bean中。

使用注解创建切面

使用我们定义的Performance接口,作为切面中切点的目标对象,然后开始使用AspecJ注解定义切面

定义切面

如下Audience类使用AspectJ注解定义了一个切面

  1. @Aspect
  2. public class Audience {
  3. //前置通知
  4. @Before("execution(** Performance.perform(..))")
  5. public void silenceCellPhones(){
  6. System.out.println("表演开始,观众就坐(silenceCellPhones)");
  7. }
  8. //前置通知
  9. @Before("execution(** Performance.perform(..))")
  10. public void takeSeats(){
  11. System.out.println("表演开始,手机调至静音(takeSeats)");
  12. }
  13. //返回通知
  14. @AfterReturning("execution(** Performance.perform(..))")
  15. public void applause(){
  16. System.out.println("表演结束,并且很精彩,观众鼓掌喝彩(applause)");
  17. }
  18. //异常通知
  19. @AfterThrowing("execution(** Performance.perform)")
  20. public void demandRefund(){
  21. System.out.println("表演失败,观众要求退款(demandRefund)");
  22. }
  23. }

上面有多个重复的切点,可以使用@Pointcut注解进行优化,performance方法内容不重要,在这里的作用实际上只是一个标识,供@Pointcut注解依附,供其他通知注解使用,避免重复使用相同的切点表达式。

  1. @Aspect
  2. public class Audience2 {
  3. @Pointcut("execution(** Performance.perform(..))")
  4. public void performance(){};
  5. //前置通知
  6. @Before("performance()")
  7. public void silenceCellPhones(){
  8. System.out.println("表演开始,观众就坐(silenceCellPhones)");
  9. }
  10. //前置通知
  11. @Before("performance()")
  12. public void takeSeats(){
  13. System.out.println("表演开始,手机调至静音(takeSeats)");
  14. }
  15. //返回通知
  16. @AfterReturning("performance()")
  17. public void applause(){
  18. System.out.println("表演结束,并且很精彩,观众鼓掌喝彩(applause)");
  19. }
  20. //异常通知
  21. @AfterThrowing("execution(** Performance.perform)")
  22. public void demandRefund(){
  23. System.out.println("表演失败,观众要求退款(demandRefund)");
  24. }
  25. }

现在定义了切点,但是如果就此而已那么Audience只会是Spring容器的一个bean,并不会视为一个切面,不会被Spring解析,也不会创建将其转换为切面的代理,需要配置以启用。

JavaConfig方式:可在配置类级别上使用@EnableAspectJ-AutoProxy注解启用自动代理。

  1. //JavaConfig配置类
  2. @Configurable
  3. @EnableAspectJAutoProxy //启用自动代理
  4. @ComponentScan //组件扫描
  5. public class ConcertConfig {
  6. @Bean
  7. public Audience audience(){
  8. return new Audience();
  9. }
  10. }

XML方式:使用Spring  aop命名空间中的<aop:aspectj-autoproxy>元素。

  1. <!--启用AspectJ自动代理-->
  2. <aop:aspectj-autoproxy />
  3. <!--声明Audience bean-->
  4. <bean class= "concert.Audience"/>

环绕通知

能让你所编写的逻辑将被通知的目标方法完全包装起来,就像同时在一个通知方法中编写前置和后置通知。如下代码,@Around注解表明watchPerformance()方法会作为performance()切点的环绕通知,其中通知方法接受一个ProceedingJoinPoint类型的参数,这个参数不许要提供,因为要在通知中通过它调用被通知的方法,在通知方法完成工作之后,需要调用ProceedingJoinPoint的oriceed()方法,否则这个通知会阻塞被通知方法(目标方法)的调用。

处理通知中的参数

目前为止,所有的切面都没有任何参数,除了环绕通知,在如下通知代码中,切点表达式匹配带参数的目标方法,其中&& args(trackNumber)表示传递给playTrack()方法的int类型参数也会传递到通知方法中,参数中的trackNumberca也与通知方法签名中的参数相匹配,此

Spring学习笔记-面向切面(AOP)-04的更多相关文章

  1. Spring学习笔记--面向切面编程(AOP)

    什么是AOP AOP(Aspect Oriented Programming),意为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的 ...

  2. Spring学习笔记IOC与AOP实例

    Spring框架核心由两部分组成: 第一部分是反向控制(IOC),也叫依赖注入(DI); 控制反转(依赖注入)的主要内容是指:只描述程序中对象的被创建方式但不显示的创建对象.在以XML语言描述的配置文 ...

  3. spring学习笔记四:AOP

    AOP(Aspect Orient Programming),面向切面编程,是对面向对象编程OOP的一种补充 面向对象编程使用静态角度考虑程序的结构,而面向切面编程是从动态角度考虑程序运行过程 AOP ...

  4. spring学习 八 面向切面编程(AOP)概述

    注:本文大部分参考   --------------------- 本文来自 -望远- 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/yanquan345/artic ...

  5. Spring实战第四章学习笔记————面向切面的Spring

    Spring实战第四章学习笔记----面向切面的Spring 什么是面向切面的编程 我们把影响应用多处的功能描述为横切关注点.比如安全就是一个横切关注点,应用中许多方法都会涉及安全规则.而切面可以帮我 ...

  6. Spring学习笔记之aop动态代理(3)

    Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...

  7. Spring框架系列(4) - 深入浅出Spring核心之面向切面编程(AOP)

    在Spring基础 - Spring简单例子引入Spring的核心中向你展示了AOP的基础含义,同时以此发散了一些AOP相关知识点; 本节将在此基础上进一步解读AOP的含义以及AOP的使用方式.@pd ...

  8. spring学习笔记(一) Spring概述

    博主Spring学习笔记整理大部分内容来自Spring实战(第四版)这本书.  强烈建议新手购入或者需要电子书的留言. 在学习Spring之前,我们要了解这么几个问题:什么是Spring?Spring ...

  9. 不错的Spring学习笔记(转)

    Spring学习笔记(1)----简单的实例 ---------------------------------   首先需要准备Spring包,可从官方网站上下载.   下载解压后,必须的两个包是s ...

随机推荐

  1. Codeforces_822

    A.小的那个数的阶乘. #include<bits/stdc++.h> using namespace std; int a,b; int main() { ios::sync_with_ ...

  2. VMware Workstation 14 Pro 安装 CentOS 7 Linux 虚拟机

    CentOS 7 下载地址:http://isoredirect.centos.org/centos/7/isos/x86_64/ ,选择 CentOS-7-x86_64-DVD-1908.iso : ...

  3. java14带参的方法

    public class jh_01_如何使用带参数的方法31 { public static void main(String[] args) { // 创建对象 ZhaZhiJi zzj = ne ...

  4. 使用 TF-IDF 加权的空间向量模型实现句子相似度计算

    使用 TF-IDF 加权的空间向量模型实现句子相似度计算 字符匹配层次计算句子相似度 计算两个句子相似度的算法有很多种,但是对于从未了解过这方面算法的人来说,可能最容易想到的就是使用字符串匹配相关的算 ...

  5. RocketMQ重试机制和消息幂等

    一.重试机制 由于MQ经常处于复杂的分布式系统中,考虑网络波动,服务宕机,程序异常因素,很有可能出现消息发送或者消费失败的问题.因此,消息的重试就是所有MQ中间件必须考虑到的一个关键点.如果没有消息重 ...

  6. 使用 Visual Studio 2015 + Python3.6 + tensorflow 构建神经网络时报错:'utf-8' codec can't decode byte 0xcc in position 78: invalid continuation byte

    使用 Visual Studio 2015 + Python3.6 + tensorflow 构建神经网络时报错:'utf-8' codec can't decode byte 0xcc in pos ...

  7. Spring Boot从入门到精通(二)配置GitHub并上传Maven项目

    简单介绍一下GitHub,它是一个面向开源及私有软件项目的托管平台,因为只支持git作为唯一的版本库格式进行托管,故名GitHub. GitHub于2008年4月10日正式上线,除了Git代码仓库托管 ...

  8. [源码分析] 从源码入手看 Flink Watermark 之传播过程

    [源码分析] 从源码入手看 Flink Watermark 之传播过程 0x00 摘要 本文将通过源码分析,带领大家熟悉Flink Watermark 之传播过程,顺便也可以对Flink整体逻辑有一个 ...

  9. springmvc maven idea 多模块开发(四):建立Web子模块

    先建立web的父模块,其他子web模块建立在该父模块之下,该模块打包方式选择为pom 建立实际web模块,右键点击web-parent,建立方法同上,打包方式为war 建立好后的目录结构如下: 手工建 ...

  10. 用C语言实现中国象棋

    基于五子棋框架上的 象棋 小游戏 本游戏是上各种水课无聊时的产物...不参考现有游戏从零开始实现各项功能. 游戏配置:二维数组,循环系统,wasd基本移动,调整窗台的函数,以及富足的发呆时间.. 完整 ...