Spring学习总结(7)-AOP
参考资料:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop
1. Aop是什么?
Aspect-oriented Programming (AOP,面向切面的编程),对于Object-oriented Programming (OOP,面向对象编程),通过提供另一种考虑程序结构的方式。OOP中模块化的关键单元是类,而在AOP中模块化的单元是方面。方面支持跨多个类型和对象的关注点(例如事务管理)的模块化。(在AOP文献中,这样的关注点通常被称为“横切”关注点。)
AOP的应用场景:日志记录、权限验证、效率检查、事务管理、Exception等等。
2. SpringAOP的底层技术
JDK动态代理 |
CGLIB代理 |
|
编译时期的织入还是运行时期的织入? |
运行时期织入 |
运行时期织入 |
初始化时期织入还是获取对象时期织入? |
初始化时期织入 |
初始化时期织入 |
3. SpringAOP和AspectJ的关系
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
早期Spring提供了一套自己的AOP语法,但过于复杂,后来的版本借助了AspectJ的语法和注解,但是底层实现还是自己的。
Spring AOP提供两种编程风格:
@AspectJ support ------------> 利用aspectj的注解
Schema-based AOP support -----------> xml aop:config 命名空间
4. Spring AOP的概念
Aspect(切面):切入业务流程的一个独立模块。
Join point(连接点):也就是业务流程在运行过程中需要插入切面的具体位置。
Pointcut(切入点):用于定义通知应该切入到哪些连接点上,不同的通知通常需要切入到不同的连接点上。
Advice(通知):是切面的具体实现方法。通知包含:位置、业务逻辑
Target object(目标对象):被一个或者多个切面所通知的对象。
AOP proxy(代理对象):将通知应用到目标对象之后被动态创建的对象。
Weaving(切入、织入):将切面应用到目标对象从而创建一个新的代理对象的过程。
5. Advice通知类型
Before 连接点执行之前,但是无法阻止连接点的正常执行,除非该段执行抛出异常。
After 连接点正常执行之后,执行过程中正常执行返回退出,非异常退出。
After throwing 执行抛出异常的时候。
After (finally) 无论连接点是正常退出还是异常退出,都会执行。
Around advice: 围绕连接点执行,例如方法调用。这是最有用的切面方式。around通知可以在方法调用之前和之后执行自定义行为。它还负责选择是继续加入点还是通过返回自己的返回值或抛出异常来快速建议的方法执行。
5.1 ProceedingJoinPoint类
ProceedingJoinPoint作为Around的方法参数使用的。而如:
@Around("pointCutTarget()")
public void around(ProceedingJoinPoint joinPoint) { }
ProceedingJoinPoint继承了JoinPoint,JoinPoint的主要方法如下:
Object getThis(); // 获取当前对象 Object getTarget(); // 获取目标对象 Object[] getArgs(); // 获取连接点的参数
ProceedingJoinPoint的主要方法是preceed(),用于调用当前方法,所以可以实现环绕通知的通知,而JoinPoint是用于获取信息,一般在@Before、@After的时候使用。
public Object proceed() throws Throwable; //作用在于调用当前方法
6. SpringAop支持AspectJ
6.1 启用@AspectJ支持
使用Java Configuration启用@AspectJ支持。要使用Java @Configuration启用@AspectJ支持,请添加@EnableAspectJAutoProxy注释。
@Configuration
@EnableAspectJAutoProxy
public class AppConfig { }
使用XML配置启用@AspectJ支持。要使用基于xml的配置启用@AspectJ支持,可以使用aop:aspectj-autoproxy元素。
<aop:aspectj-autoproxy/>
6.2 声明一个切面
申明一个@Aspect注释类,并且定义成一个bean交给Spring管理。切面默认是单例类。
@Component
@Aspect
public class UserAspect { }
如果需要每次让切面类都是实例类:
@Component
@Aspect
@Scope("prototype")
public class UserAspect { }
如果只想在指定bean操作时,创建新的实例类:
@Component
@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
@Scope("prototype")
public class UserAspect { }
6.3 声明一个切点
切入点表达式由@Pointcut注释表示。切入点声明由两部分组成:一个签名包含名称和任何参数,以及一个切入点表达式,该表达式确定我们对哪个方法执行感兴趣。
@Pointcut("execution(* com.yao.dao.UserDao.*(..))")
public void pintCut(){
System.out.println("point cut");
}
6.4 声明一个Advice通知
advice通知与pointcut切入点表达式相关联,并在切入点匹配的方法执行@Before之前、@After之后或前后运行。
@Before("com.yao.aop.UserAspect.pintCut()")
public void beforeAdvice(){
System.out.println("before");
}
advice后面可以跟多个切点,并使用符号:|| && !
例如:@Before("pointCutWithin() && !pointCutArgs()") 表示包含pointCutWithin()规则,但不包含pointCutArgs()规则
7. 各种连接点joinPoint的意义
7.1 execution
用于匹配方法执行 join points连接点,最小粒度方法,在aop中主要使用。
公式:execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
这里问号表示当前项可以有也可以没有,其中各项的语义如下:
modifiers-pattern:方法的可见性,如public,protected;
ret-type-pattern:方法的返回值类型,如int,void等;
declaring-type-pattern:方法所在类的全路径名,如com.spring.Aspect;
name-pattern:方法名类型,如buisinessService();
param-pattern:方法的参数类型,如java.lang.String;
throws-pattern:方法抛出的异常类型,如java.lang.Exception;
例子:
@Pointcut("execution(* com.chenss.dao.*.*(..))") //匹配com.chenss.dao包下的任意接口和类的任意方法
@Pointcut("execution(public * com.chenss.dao.*.*(..))") //匹配com.chenss.dao包下的任意接口和类的public方法
@Pointcut("execution(public * com.chenss.dao.*.*())") //匹配com.chenss.dao包下的任意接口和类的public 无方法参数的方法
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String, ..))") //匹配com.chenss.dao包下的任意接口和类的第一个参数为String类型的方法
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String))") //匹配com.chenss.dao包下的任意接口和类的只有一个参数,且参数为String类型的方法
@Pointcut("execution(public * *(..))") //匹配任意的public方法
@Pointcut("execution(* te*(..))") //匹配任意的以te开头的方法
@Pointcut("execution(* com.chenss.dao.IndexDao.*(..))") //匹配com.chenss.dao.IndexDao接口中任意的方法
@Pointcut("execution(* com.chenss.dao..*.*(..))") //匹配com.chenss.dao包及其子包中任意的方法
关于这个表达式的详细写法,可以脑补也可以参考官网很容易的:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop-pointcuts-examples
由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的信息,并且在Spring中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。
7.2 Within
表达式的最小粒度为类。within与execution相比,粒度更大,仅能实现到包和接口、类级别。而execution可以精确到方法的返回值,参数个数、修饰符、参数类型等。
例子:
@Pointcut("within(com.chenss.dao.*)") //匹配com.chenss.dao包中的任意方法
@Pointcut("within(com.chenss.dao..*)") //匹配com.chenss.dao包及其子包中的任意方法
7.3 Args
args表达式的作用是匹配指定参数类型和指定参数数量的方法,与包名和类名无关。
args同execution不同的地方在于:args匹配的是运行时传递给方法的参数类型;execution(* *(java.io.Serializable))匹配的是方法在声明时指定的方法参数类型。
例子:
@Pointcut("args(java.io.Serializable)") //匹配运行时传递的参数类型为指定类型的、且参数个数和顺序匹配
@Pointcut("@args(com.chenss.anno.Chenss)") //接受一个参数,并且传递的参数的运行时类型具有@Classified
7.4 this
表示动态代理的当前代理对象。JDK代理时,指向接口和代理类proxy,cglib代理时 指向接口和子类(不使用proxy)
7.5 target
表示动态代理的目标对象。指向接口和子类 此处需要注意的是,如果配置设置@EnableAspectJAutoProxy(proxyTargetClass=false),或默认为false,则是用JDK代理,否则使用的是CGLIB代理。JDK代理的实现方式是基于接口实现,代理类继承Proxy,实现接口,而CGLIB继承被代理的类来实现。所以使用target会保证目标不变,关联对象不会受到这个设置的影响。但是使用this对象时,会根据该选项的设置,判断是否能找到对象。
例子:
@Pointcut("target(com.chenss.dao.IndexDaoImpl)") //目标对象,也就是被代理的对象。限制目标对象为com.chenss.dao.IndexDaoImpl类
@Pointcut("this(com.chenss.dao.IndexDaoImpl)") //当前对象,也就是代理对象,代理对象时通过代理目标对象的方式获取新的对象,与原值并非一个
@Pointcut("@target(com.chenss.anno.Chenss)") //具有@Chenss的目标对象中的任意方法
@Pointcut("@within(com.chenss.anno.Chenss)") //等同于@targ
7.6 @target、@args、@within、@annotation
匹配方法级别,上述所有表达式都有@ 比如@Target(里面是一个注解类xx,表示所有加了xx注解的类,和包名无关)
注意:上述所有的表达式可以混合使用,|| && !
例子:
@Pointcut("@annotation(com.chenss.anno.Chenss)") //匹配带有com.chenss.anno.Chenss注解的方法
7.7 bean
指定Spring内声明的bean名称
例子:
@Pointcut("bean(dao1)")//名称为dao1的bean上的任意方法
@Pointcut("bean(dao*)")
8. Spring AOP XML实现方式
注意事项:
(1)在aop:config中定义切面逻辑,允许重复出现,重复多次,以最后出现的逻辑为准,但是次数以出现的次数为准
(2)aop:aspect ID重复不影响正常运行,依然能够有正确结果
(3)aop:pointcut ID重复会出现覆盖,以最后出现的为准。不同aop:aspect内出现的pointcut配置,可以相互引用
<?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"
xmlns:context="http://www.springframework.org/schema/context"
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.chenss"></context:component-scan> <!-- 定义AspectJ对象使用的逻辑类,类中提供切面之后执行的逻辑方法 -->
<bean id="aspectAop" class="com.chenss.aspectj.Aspect"></bean>
<bean id="aspectAop2" class="com.chenss.aspectj.Aspect2"></bean> <bean id="indexDao" class="com.chenss.entity.IndexDao"></bean> <!--在Config中定义切面逻辑,允许重复出现,重复多次,以最后出现的逻辑为准,但是次数以出现的次数为准-->
<aop:config>
<!-- aop:aspect ID重复不影响正常运行,依然能够有正确结果 -->
<!-- aop:pointcut ID重复会出现覆盖,以最后出现的为准。不同aop:aspect内出现的pointcut配置,可以相互引用 -->
<aop:aspect id="aspect" ref="aspectAop">
<aop:pointcut id="aspectCut" expression="execution(* com.chenss.entity.*.*())"/>
<aop:before method="before" pointcut-ref="aspectCut"></aop:before>
fffffff
<aop:pointcut id="aspectNameCut" expression="execution(* com.chenss.entity.*.*(java.lang.String, ..))"/>
<aop:before method="before2" pointcut-ref="aspectNameCut"></aop:before>
</aop:aspect>
</aop:config>
</beans>
Spring学习总结(7)-AOP的更多相关文章
- Spring学习笔记之aop动态代理(3)
Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点: 1.在该系统中有多少的dao就的写多少的proxy,麻烦 2.如果目标接口有方法的改动,则proxy也需要改动. Person ...
- Spring学习笔记4——AOP
AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能. 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 ...
- Spring 学习十五 AOP
http://www.hongyanliren.com/2014m12/22797.html 1: 通知(advice): 就是你想要的功能,也就是安全.事物.日子等.先定义好,在想用的地方用一下.包 ...
- spring学习 十三 注解AOP
spring 不会自动去寻找注解,必须告诉 spring 哪些包下的类中可能有注解,也就是要开启注解扫描,注解的包是spring-context.jar,所以在配置文件中还要引入context约束,也 ...
- [Spring学习笔记 4 ] AOP 概念原理以及java动态代理
一.Spring IoC容器补充(1) Spring IoC容器,DI(依赖注入): 注入的方式:设值方法注入setter(属性注入)/构造子注入(构造函数传入依赖的对象)/字段注入Field(注解) ...
- spring 学习之二 AOP编程
AOP概念 AOP, aspect oriented programing,翻译过来就是面向切面编程的意思,那什么叫面向切面编程呢?相对于之前传统的纵向继承方式来对原有功能进行功能扩展, 面向切面编程 ...
- Spring学习笔记2—AOP
1.AOP概念 AOP(Aspect Oriented Programming):面向切面编程,AOP能够将那些与业务无关,却为业务模块所共同调用的应用(例如事务处理.日志管理.权限控制等)封装起来, ...
- spring学习06(AOP)
9.AOP 什么是AOP AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软 ...
- Spring学习笔记之AOP配置篇(一)
[TOC] 1. 创建并声明一个切面 首先,创建一个类,添加@Component注解使其添加到IoC容器 然后,添加@Aspect注解,使其成为一个切面 最后,在配置文件里面,使用<aop:as ...
随机推荐
- salesman,动态规划带一点点贪心。
题目直接链接 分析一下: 这题题意还是比较明白的(少见的一道中文题),他的意思就是:有这么一个无向图:保证联通且点与点直接有唯一的简单路径(说白了就是棵树,根节点是1),每个节点有一个权值(有正有负) ...
- day50 前端入门
目录 一.引子 1 前端学习的历程 2 浏览器与http协议 2.1 浏览器窗口输入网址回车后发生了几件事 2.2 http协议 二.html入门 1 标签的分类 2 head内常用的标签 3 bod ...
- mysql两种重要的引擎
其中MyISAM:不支持事物,表锁 .frm : 表结构定义文件 .MYD: 表数据 .MYI:索引文件 InnoDB:支持事物,行锁 .frm : 表结构定义文件 .ibd:表空间(数据和索引)
- 你是如何理解Vue的响应式系统的
1.响应式系统简述: 任何一个 Vue Component 都有一个与之对应的 Watcher 实例. Vue 的 data 上的属性会被添加 getter 和 setter 属性. 当 Vue Co ...
- scrapy 基础组件专题(四):信号运用
一.scrapy信号使用的简单实例 import scrapy from scrapy import signals from ccidcom.items import CcidcomItem cla ...
- 数据可视化之PowerQuery篇(十一)使用Power BI进行动态帕累托分析
https://zhuanlan.zhihu.com/p/57763423 上篇文章介绍了帕累托图的用处以及如何制作一个简单的帕累托图,在 PowerBI 中可以很方便的生成,但若仅止于此,并不足以体 ...
- ES6的功能简介
1. let, const, var let: 块级作用域, 不存在变量提升, 值可更改 const:块级作用域, 不能存在变量提升, 值不可更改 var: 函数级作用域, 变量提升, 值可更改 案例 ...
- 一文读懂对抗生成学习(Generative Adversarial Nets)[GAN]
一文读懂对抗生成学习(Generative Adversarial Nets)[GAN] 0x00 推荐论文 https://arxiv.org/pdf/1406.2661.pdf 0x01什么是ga ...
- freeMarker随手笔记
freemarker官网:http://docs.freemarker.cn/ 注意: 1.如果标签没有嵌套内容(在开始标签和结束标签之间的内容),那么可以只使用开始标签 (详情:http://fre ...
- 如何将你写的脚本程序打包成一个exe可执行程序
编写的程序打包成一个exe文件,随时可以双击执行,想想是不是很酷.接下来我们一起看一下如何将自己编写的程序打包为一个exe的可执行程序. 将程序打包成exe的好处 除了满足自己的成就感以外, ...