AOP基本概念的理解

面向切面AOP主要是在编译期或运行时,对程序进行织入,实现代理,

对原代码毫无侵入性,不破坏主要业务逻辑,减少程序的耦合度。

  • 主要应用范围:

    日志记录,性能统计,安全控制,事务处理,异常处理等等

名词性概念

  • 切面(Aspect)

    通常是一个类,在里面可以定义切入点和通知,即切面=切入点+通知
  • 连接点(Joint Point)

    被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring 中连接点指的就是被拦截的到的方法,实际上连接点还可以是字段或者构造器。
  • 切入点(Pointcut)

    对连接点进行拦截的定义。
  • 通知(Advice)

    拦截到连接点之后所要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。
  • AOP 代理

    AOP 框架创建的对象,代理就是目标对象的加强。Spring 中的 AOP 代理可以使 JDK 动态代理,也可以是 CGLIB 代理,前者基于接口,后者基于子类。
  • 织入(Weaving)

    把切面加入到对象,并创建出代理对象的过程。

动态代理

在运行期间生成对象进行代理,

spring AOP就是动态代理。

静态代理

自己编写代理对象,在编译器织入,

AspectJ就是在编译期间进行织入,从而减少对运行时效率的影响。

SpringAOP

根据对象是否是实现类选择代理的方法

  • 如果要代理的对象实现了接口,spring AOP会根据接口,使用JDK Proxy创建代理

  • 如果没有实现接口,则通过CGLIB代理

当然也可以指定都使用CGLIB进行切入,而JDK方法不适用于没有接口实现的目标类

对于JDK proxy

Jdk proxy会实现目标类的接口,代理逻辑就在新的实现类中

只能对实现类进行代理,性能也优于CGLIB,所以平时都是分为"接口-实现iml"来设计。

对于CGLIB

cglib会创建一个代理目标类的子类,而代理逻辑就在这一子类中添加,

然后得到这一子类的对象,也就是代理增强后的对象,一切都是动态的,

具体实现有待学习。

切面类

使用@Aspect注解定义切面类

比如这样

@Component
@Aspect
@Oder(99)
public class WebLogAspect {}

另外对同一个方法有多个切面进行代理的时候,难免需要区分执行顺序,

这时候可以使用@Order注解定义优先级,数字越低,级别越高。

切面Advice

执行顺序around -> before -> around -> after -> afterRuternning

@After

第一个参数都必须是JoinPoint类型

在目标方法完成后通知,

无论方法是以何种方式完成,异常也是如此

@After-returning

第一个参数都必须是JoinPoint类型

结束并安全返回时通知,异常不通知

@After-throwing

第一个参数都必须是JoinPoint类型

异常时通知

@Before

第一个参数都必须是JoinPoint类型

顾名思义

@Around

最强大的通知

第一个形参必须是ProceedingJoinPoint类型,

public interface ProceedingJoinPoint extends JoinPoint {
void set$AroundClosure(AroundClosure var1); default void stack$AroundClosure(AroundClosure arc) {
throw new UnsupportedOperationException();
} Object proceed() throws Throwable; Object proceed(Object[] var1) throws Throwable;
}

可以看到它继承自JoinPoint,多了proceed方法

注解的方法体内调用ProceedingJoinPoint参数的proceed()方法才会执行目标。

调用这个方法时,还可以传入一个Object[]对象作为参数

可以通过这个切面决定方法是否执行,改变传入参数,改变返回值,检查异常等

参数方法

  • getArgs(): Returns the method arguments.

  • getThis(): Returns the proxy object.

  • getTarget(): Returns the target object.

  • getSignature(): Returns a description of the method that is being advised.

  • toString(): Prints a useful description of the method being advised.

切点表达式

有关切点表达式,建议阅读 传送门

可以定义一个切点,之后就不用一一指定,直接带入value即可,例如:

@Pointcut("execution(* com.hyg.app.controller..*.*(..))")
public void webLog(){} @Before(value = "webLog()")
public void doBefore (JoinPoint jp){
String name = jp.getSignature().getName();
System.out.println(name+"开始执行");
}

execution

表达式中最常用的方法是execution,粒度最小

对于execution(* com.hyg.app.controller..*.*(..))

  • execution 表达式的类型指定
  • 第一个* 代表 任意的返回值类型
  • com.jiuxian aop所切的包名
  • 包后面.. 表示当前包其子包,一个.是当前包,两个.就包括所有子包
  • 第二个* 表示类名,代表所有类
  • .*(..) 表示任何方法, 括号代表参数 .. 表示任意参数

后面那串东西,可以记为每一个.都是更深的一个粒度

来个精确点的示例:

execution(* com.hyg.app.service.*Service.add*(String))

表示所有类型的,com.hyg.app.service包下的,

所有以Service结尾的类,

add开头的,参数类型为String的方法

例子

在官方文档中有很多示例,如下

所有public方法
execution(public * *(..)) 所有名字以set开头的方法
execution(* set*(..)) 所有AccountService中实现的接口的方法
execution(* com.xyz.service.AccountService.*(..)) 所有service包下的方法
execution(* com.xyz.service.*.*(..)) 所有在service包以及子包下的方法
execution(* com.xyz.service..*.*(..)) within(com.xyz.service.*) 所有service包下方法
within(com.xyz.service..*) 所有service包和子包下方法
this(com.xyz.service.AccountService) 匹配accountservice代理的对象
target(com.xyz.service.AccountService) 实现了AccountService接口的对象 拥有transactional注解的
@annotation(org.springframework.transaction.annotation.Transactional)
传递的参数是Serializable的
args(java.io.Serializable):

关于execution和within的区别

execution可以指定方法返回类型,类名,方法名和参数名等与方法相关的部件,

而within的最小粒度是类。

关于this和target的区别

this匹配的是代理类,即目标对象被代理后的代理对象

target则是匹配普通的目标对象

以下情况外,二者的效果都是一致的。

this(SomeObject)或target(SomeObject),这里SomeObject实现了某个接口:对于这种情况,虽然表达式中指定的是一种具体的对象类型,但由于其实现了某个接口,因而Spring默认会使用Jdk代理为其生成代理对象,Jdk代理生成的代理对象与目标对象实现的是同一个接口,但代理对象与目标对象还是不同的对象,由于代理对象不是SomeObject类型的,因而此时是不符合this语义的,而由于目标对象就是SomeObject类型,因而target语义是符合的,此时this和target的效果就产生了区别;这里如果强制Spring使用Cglib代理,因而生成的代理对象都是SomeObject子类的对象,其是SomeObject类型的,因而this和target的语义都符合,其效果就是一致的。

args

用于指定参数类型,类型必须是全路径的

官网解释

  • execution: For matching method execution join points. This is the primary pointcut designator to use when working with Spring AOP.
  • within: Limits matching to join points within certain types (the execution of a method declared within a matching type when using Spring AOP).
  • this: Limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.
  • target: Limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type.
  • args: Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.
  • @target: Limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type.
  • @args: Limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given types.
  • @within: Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP).
  • @annotation: Limits matching to join points where the subject of the join point (the method being executed in Spring AOP) has the given annotation.

---官方文档---

我的博客:https://www.seyana.life/post/12

AOP和spring AOP学习记录的更多相关文章

  1. Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客

    ==他的博客应该不错,没有细看 Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客 http://blog.csdn.net/u012706811/article/det ...

  2. 我的Spring Boot学习记录(二):Tomcat Server以及Spring MVC的上下文问题

    Spring Boot版本: 2.0.0.RELEASE 这里需要引入依赖 spring-boot-starter-web 这里有可能有个人的误解,请抱着怀疑态度看. 建议: 感觉自己也会被绕晕,所以 ...

  3. 【AOP】Spring AOP基础 + 实践 完整记录

    Spring AOP的基础概念 ============================================================= AOP(Aspect-Oriented Pr ...

  4. 死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  5. AOP及spring AOP的使用

    介绍 AOP是一种概念(思想),并没有设定具体语言的实现. AOP是对oop的一种补充,不是取而代之. 具体思想:定义一个切面,在切面的纵向定义处理方法,处理完成之后,回到横向业务流. 特征 散布于应 ...

  6. 自己实现 aop 和 spring aop

    上文说到,我们可以在 BeanPostProcessor 中对 bean 的初始化前化做手脚,当时也说了,我完全可以生成一个代理类丢回去. 代理类肯定要为用户做一些事情,不可能像学设计模式的时候创建个 ...

  7. 死磕Spring之AOP篇 - Spring AOP常见面试题

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  8. 死磕Spring之AOP篇 - Spring AOP总览

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  9. 死磕Spring之AOP篇 - Spring AOP自动代理(一)入口

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

随机推荐

  1. docker常用的命令-在自己心情低落的时候,告诫自己不要把负能量带给别人。

    daocker基础命令:https://www.cnblogs.com/xiaowenshu/p/10474746.html 一.Docker常用命令 安装部署好Dokcer后,执行的命令是docke ...

  2. [LC] 438. Find All Anagrams in a String

    Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. Strings ...

  3. 复习break、continue、while、do-while的运用

    一.复习: 循环.反复执行某段语句一种语法形式. 1.基本语法: for( 初始条件 ; 循环条件 ; 状态的改变 ) { 循环体 } 循环的四要素. 循环的执行过程.初始条件--循环条件--循环体- ...

  4. LeetCode No.70,71,72

    No.70 ClimbStairs 爬楼梯 题目 假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. ...

  5. android cpu affinity

    暂时无法获取当前线程运行在哪个CPU上,待调查... int omask = 0; int nmask = 0xF0; static void affinity() { int err; int sy ...

  6. https协议 和 Charles 进行https抓包原理

    本文转载自:https://blog.csdn.net/fox64194167/article/details/80387696 1.对称加密 其变成复杂的加密密文发送出去.收信方收到密文后,若想解读 ...

  7. Linux和git使用

    一.Linux ​ cd . .. - ~ ls -a h l 通配符 mkdir bouch nano vim cat clear cp -r ./db/ ./lib/ mv -r rm -r wh ...

  8. shell-变量学习-01

    1.变量   1.1 变量赋值 > variable_zhou="hello world!" #等号两边不能有空格   1.2 使用变量 > echo $variabl ...

  9. <JZOJ5941>乘

    emmm还挺妙 不过我没想到qwq 考场上瞎写的还mle了心碎 把b分两..预处理下 O1询问qwq #include<cstdio> #include<iostream> # ...

  10. iOS(Swift)学习笔记之去除UINavigationBar下方横线

    本文为原创文章,转载请标明出处 // 去除UINavigationBar下方横线 navigationController.navigationBar.shadowImage = UIImage() ...