参考资料: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的更多相关文章

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

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

  2. Spring学习笔记4——AOP

    AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能. 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 ...

  3. Spring 学习十五 AOP

    http://www.hongyanliren.com/2014m12/22797.html 1: 通知(advice): 就是你想要的功能,也就是安全.事物.日子等.先定义好,在想用的地方用一下.包 ...

  4. spring学习 十三 注解AOP

    spring 不会自动去寻找注解,必须告诉 spring 哪些包下的类中可能有注解,也就是要开启注解扫描,注解的包是spring-context.jar,所以在配置文件中还要引入context约束,也 ...

  5. [Spring学习笔记 4 ] AOP 概念原理以及java动态代理

    一.Spring IoC容器补充(1) Spring IoC容器,DI(依赖注入): 注入的方式:设值方法注入setter(属性注入)/构造子注入(构造函数传入依赖的对象)/字段注入Field(注解) ...

  6. spring 学习之二 AOP编程

    AOP概念 AOP, aspect oriented programing,翻译过来就是面向切面编程的意思,那什么叫面向切面编程呢?相对于之前传统的纵向继承方式来对原有功能进行功能扩展, 面向切面编程 ...

  7. Spring学习笔记2—AOP

    1.AOP概念 AOP(Aspect Oriented Programming):面向切面编程,AOP能够将那些与业务无关,却为业务模块所共同调用的应用(例如事务处理.日志管理.权限控制等)封装起来, ...

  8. spring学习06(AOP)

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

  9. Spring学习笔记之AOP配置篇(一)

    [TOC] 1. 创建并声明一个切面 首先,创建一个类,添加@Component注解使其添加到IoC容器 然后,添加@Aspect注解,使其成为一个切面 最后,在配置文件里面,使用<aop:as ...

随机推荐

  1. 如何让touchmove之后不触发touchend的事件

    手机扫码看效果 不多说,直接上代码 <ul id="Ul"> <li>111</li> <li>222</li> < ...

  2. python 并发专题(十二):基础部分补充(四)协程

    相关概念: 协程:一个线程并发的处理任务 串行:一个线程执行一个任务,执行完毕之后,执行下一个任务 并行:多个CPU执行多个任务,4个CPU执行4个任务 并发:一个CPU执行多个任务,看起来像是同时执 ...

  3. Kubernetes部署通用手册 (支持版本1.19,1.18,1.17,1.16)

    Kubernetes平台环境规划 操作环境 rbac 划分(HA高可用双master部署实例) 本文穿插了ha 高可用部署的实例,当前章节设计的是ha部署双master 部署 内网ip 角色 安装软件 ...

  4. 原来不只是fastjson,这个你每天都在用的类库也被爆过反序列化漏洞!

    GitHub 15.8k Star 的Java工程师成神之路,不来了解一下吗! GitHub 15.8k Star 的Java工程师成神之路,真的不来了解一下吗! GitHub 15.8k Star ...

  5. js&jsp规范问题

    1.js初始化问题    一般与数据库交互的需要进行初始化,固定控件一般不需要初始化.有些需要整体浏览器页面校准的可能需要初始化.    //初始化操作按钮        $(function(){  ...

  6. Cyber Security - Palo Alto Firewall Objects Addresses, Services, and Groups(2)

    Users Objects and Groups Creating local user objects. Creating local user groups. https://docs.paloa ...

  7. 查看锁信息 v$lock 和 v$locked_object

    查看锁住的对象及会话id,serial# select a.*  from (SELECT o.object_name,               l.locked_mode,            ...

  8. vue : 自定义脚手架提示

    做项目做烦了就想找点乐子. 比如,我们可以自定义脚手架提示.  webpack.dev.conf.js  54-78 行 module.exports = new Promise((resolve, ...

  9. 题解 CF786B 【Legacy】

    本题要求我们支持三种操作: ① 点向点连边. ② 点向区间连边. ③ 区间向点连边. 然后跑最短路得出答案. 考虑使用线段树优化建图. 建两颗线段树,入树和出树,每个节点为一段区间的原节点集合.入树内 ...

  10. css的一些小技巧。修改input样式

    在第一次正式写项目的时候,遇到了几个布局的小技巧.记录一下. 我们常常会遇到图片和文字对齐的一种样式.比如 这样的样式,我们写的时候有时候会出现不对齐的情况.我们有俩种方法 一种就是flex的布局,还 ...