一、什么是AOP

与OOP对比,AOP是处理一些横切性问题,这些横切性问题不会影响到主逻辑实现的,但是会散落到代码的各个部分,难以维护。一键获取源码地址spring aop面试题

AOP就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。

二、 AOP的应用场景

· 日志记录

· 权限验证

· 效率检查

· 事务管理

三、Spring AOP原理及其应用

3.1 AOP相关概念

· Aspect(切面): 通常是一个类(交给Spring容器管理),里面可以定义切入点和通知

· JointPoint(连接点): 程序执行过程中的一个点,如方法的执行或异常的处理

· Advice(通知): AOP在特定的切入点上执行的增强处理

· 通知类型:

· Before advice

· After returning advice

· After throwing advice

· After (finally) advice

· Around advice

· 调用顺序:

· Around advice>Before advice>After (finally) advice>After returning advice/After throwing advice

· Pointcut(切入点): 连接点的集合

· Target object(目标对象):被通知对象

· AOP proxy:AOP框架创建的对象,代理就是目标对象的增强。

· JDK dynamic proxy

· CGLIB proxy

· 思考: 初始化时织入还是获取对象时织入?

· Weaving(织入):把代理逻辑加入到目标对象上的过程叫做织入

3.2 AOP的应用

3.2.1 Spring AOP with AspectJ pointcuts

Schema-based AOP Support

xml配置对AOP支持的 后置处理器

AspectJAwareAdvisorAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator // 配置 aop:aspectj-autoproxy/

spring-aop.xml

bat.ke.qq.com.config.XmlAspect"/>

public class XmlAspect { public void before(JoinPoint point) { System.out.println(“before”); } public void after() { System.out.println(“after”); }}

@AspectJ support

注解配置对AOP支持的 后置处理器

AnnotationAwareAspectJAutoProxyCreator

利用aspectj的注解

@Configuration@EnableAspectJAutoProxypublic class AppConfig {}

@Aspect@Componentpublic class AspectConfig { //@Pointcut(“execution(* bat.ke.qq.com.dao.*.*(…))”) //@Pointcut(“within(bat.ke.qq.com.dao.*)”) //@Pointcut(“args(String)”) //@Pointcut(“this(bat.ke.qq.com.dao.FoxDao)”) // jdk动态代理 extend Proxy implements IFoxDao //@Pointcut(“target(bat.ke.qq.com.dao.FoxDao)”) //@Pointcut(“args(String …) || args()”) //@Pointcut(“execution(* bat.ke.qq.com.dao.*.*(String))”) //@Pointcut(“@annotation(bat.ke.qq.com.anno.Yuanma)”) //@Pointcut(“@target(bat.ke.qq.com.anno.Dao)”) // 目标是注解配置 //@Pointcut(“@within(bat.ke.qq.com.anno.Dao)”) //@Pointcut(“@args(bat.ke.qq.com.anno.Dao)”) //传参类型配置@Dao的类型 @Pointcut(“bean(foxDao)”) private void pointcut() { } @Before(“pointcut()”) public void before(JoinPoint point) { point.getThis(); System.out.println(“before”); } @After(“pointcut()”) public void after() { System.out.println(“after”); } @AfterReturning(“pointcut()”) public void afterReturning() { System.out.println(“afterReturning”); } @AfterThrowing(“pointcut()”) public void afterThrwoing() { System.out.println(“afterThrwoing”); } @Around(“pointcut()”) public Object around(ProceedingJoinPoint point) throws Throwable { System.out.println(“around”); Object[] args = point.getArgs(); for(int i=0;i<args.length;i++){ System.out.println(“====args:”+args[i]); if(args[i].getClass().equals(String.class)){ args[i] += “xxxx”; } } Object result = point.proceed(args); return result; }}

3.2.2 Spring AOP with auto-proxy

BeanNameAutoProxyCreator

通过BeanNameAutoProxyCreator指定beanName 实现代理逻辑

//使用BeanNameAutoProxyCreator来创建代理@Beanpublic BeanNameAutoProxyCreator beanNameAutoProxyCreator(){ BeanNameAutoProxyCreator beanNameAutoProxyCreator=new BeanNameAutoProxyCreator(); //设置要创建代理的 beanNames
beanNameAutoProxyCreator.setBeanNames(“*Service”); //设置拦截链名字(有先后顺序) 通知 beanNameAutoProxyCreator.setInterceptorNames(“aopMethodInterceptor”); return beanNameAutoProxyCreator;}

DefaultAdvisorAutoProxyCreator

根据Advisor的匹配机制自动创建代理,会对容器中所有的Advisor进行扫描,自动将这些切面应用到匹配的Bean中,实现类
DefaultAdvisorAutoProxyCreator

@Beanpublic
NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor(){ NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor= new NameMatchMethodPointcutAdvisor(); // 方法级别 nameMatchMethodPointcutAdvisor.setMappedNames(“query*”,“find*”); nameMatchMethodPointcutAdvisor.setAdvice(aopMethodInterceptor()); return nameMatchMethodPointcutAdvisor;}@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){ return new DefaultAdvisorAutoProxyCreator();}

3.2.3 pointcut的配置分析

1.execution

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:方法所在类的全路径名,如bat.ke.qq.com.dao.FoxDao;name-pattern:方法名类型,如userService(),必须配置;param-pattern:方法的参数类型,如java.lang.String,必须配置;throws-pattern:方法抛出的异常类型,如java.lang.Exception;

方法级别的,广泛应用,ret-type-pattern和name-pattern(param-pattern) 是必须的

@Pointcut(“execution(* bat.ke.qq.com.dao.*.*(…))”)

2.within

表达式的最小粒度为类

@Pointcut(“within(bat.ke.qq.com.dao.*)”)

3.this

代理对象

// jdk动态代理 基于接口 extend Proxy implements IFoxDao 只支持接口和Proxy// cglib 基于继承,支持接口和目标类@Pointcut(“this(bat.ke.qq.com.dao.FoxDao)”)

4.target

目标对象

@Pointcut(“target(bat.ke.qq.com.dao.FoxDao)”)

5.args

args表达式的作用是匹配指定参数类型和指定参数数量的方法,与包名和类名无关

@Pointcut(“args(String)”)@Pointcut(“args(String …) || args()”)

6.@target

目标对象有配置@Dao注解

@Pointcut(“@target(bat.ke.qq.com.anno.Dao)”)

7.@args

传参类型配置@Dao的类型

@Pointcut(“@args(bat.ke.qq.com.anno.Dao)”)

8.@within

9.@annotation

作用方法级别,配置@Yuanma

@Pointcut(“@annotation(bat.ke.qq.com.anno.Yuanma)”)

10.bean

指定bean

@Pointcut(“bean(foxDao)”)@Pointcut(“bean(*Service)”)

注意: 上述所有的表达式可以混合使用,|| && !

3.2.4 Advice的使用

通知类型

· Before adviceAfter

· returning advice

· After throwing advice

· After (finally) advice

· Around advice

Proceedingjoinpoint 和JoinPoint

Proceedingjoinpoint 和JoinPoint的区别:Proceedingjoinpoint 继承了JoinPoint,proceed()这个是aop代理链执行的方法。`JoinPoint的方法1.java.lang.Object[] getArgs():获取连接点方法运行时的入参列表; 2.Signature getSignature() :获取连接点的方法签名对象; 3.java.lang.Object getTarget() :获取连接点所在的目标对象; 4.java.lang.Object getThis() :获取代理对象本身;proceed()有重载,有个带参数的方法,可以修改目标方法的的参数

4. AOP的源码分析

AopProxyFactory //AOP代理工厂AopProxy //AOP代理 getProxy获取到代理对象 AbstractAutoProxyCreator // 代理对象的抽象后置处理器

在bean的initializeBean方法的
applyBeanPostProcessorsAfterInitialization中调用

AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)>AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization>AbstractAutoProxyCreator#postProcessAfterInitialization> AbstractAutoProxyCreator#wrapIfNecessary> //创建代理对象Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

通过AopProxyFactory获取AopProxy

ProxyCreatorSupport#createAopProxy>DefaultAopProxyFactory#createAopProxy// JDK动态代理和Cglib的选择if (config.isOptimize() || config.isProxyTargetClass() ||
hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " +“Either an interface or a target is required for proxy creation.”); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config);}else { return new JdkDynamicAopProxy(config);}

JDK dynamic proxy

在Proxy这个类当中首先实例化一个对象ProxyClassFactory,然后在get方法中调用了apply方法,完成对代理类的创建

JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)> Proxy#newProxyInstance> Proxy#
getProxyClass0proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());>ProxyClassFactory#apply// generateProxyClass: 通过反射收集字段和属性然后生成字节码byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);// defineClass0: jvm内部完成对上述字节码的loadreturn defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);

CGLIB proxy

cglib封装了ASM这个开源框架,对字节码操作,完成对代理类的创建。主要通过集成目标对象,然后完成重写,再操作字节码。

org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)

总结:

cglib是通过继承来操作子类的字节码生成代理类,JDK是通过接口,然后利用java反射完成对类的动态创建,严格意义上来说cglib的效率高于JDK的反射,但是这种效率取决于代码功力,其实可以忽略不计。

一文搞懂Spring AOP源码底层原理相关推荐

  1. 轻轻松松看懂Spring AOP源码

    轻轻松松看懂Spring AOP源码 https://baijiahao.baidu.com/s?id=1596466083334197175&wfr=spider&for=pc 如果 ...

  2. 一文搞懂Spring,堪称Spring源码终结者

    Spring的影响力想必无需与大家多说,如果你用spring,那么读读源码有助于对你最重要的工具的理解,好的框架源码也可以帮助我们理解什么是好代码. 刚参加工作那会,没想过去读源码,更没想过去改框架的 ...

  3. 76 张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!

    下面我会简单介绍一下 AOP 的基础知识,以及使用方法,然后直接对源码进行拆解. 不 BB,上文章目录. 1. 基础知识 1.1 什么是 AOP ? AOP 的全称是 "Aspect Ori ...

  4. 【Spring】Spring AOP源码分析-导读(一)

    文章目录 1.简介 2.AOP 原理 3.AOP 术语及相应的实现 3.1 连接点 - Joinpoint 3.2 切点 - Pointcut 3.3 通知 - Advice 3.4 切面 - Asp ...

  5. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  6. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  7. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  8. Spring AOP 源码系列(一)解析 AOP 配置信息

    在进行源码阅读之前建议先看一下这篇文章:Spring AOP 源码分析系列文章导读 by 田小波,写的非常好,推荐阅读. 关于 AOP 中常用的一些术语这里就不解释了,如果不清楚的建议先看一遍上面推荐 ...

  9. spring AOP源码分析(一)

    spring AOP源码分析(一) 对于springAOP的源码分析,我打算分三部分来讲解:1.配置文件的解析,解析为BeanDefination和其他信息然后注册到BeanFactory中:2.为目 ...

最新文章

  1. 使用TaskManager爬取2万条代理IP实现自动投票功能
  2. ftp服务器 文件目录,如何列出ftp服务器上的目录中的文件?
  3. Qt中如何获取系统图标
  4. 二、mysql数据类型
  5. Object调用静态方法
  6. 阿里云服务器 CentOS 7上-- Docker 安装 网关(API-Getway)--KONG
  7. [LibTorch] C++ 调用 PyTorch 导出的模型
  8. 链表反转的两种实现方法,后一种击败了100%的用户
  9. how tomcat works 读书笔记(一)----------一个简单的webserver
  10. 音视频编解码:NVIDIA Jetson Linux Multimedia API(总结)
  11. 删除部分mysql日志_正确删除MYSQl日志方法
  12. MyBatis Review——多对多映射
  13. Boost C++ 智能指针
  14. 安川控制器MP3300与C# 上位机通讯
  15. 苹果计算机远程控制软件,向日葵远程控制软件iPhone手机远程控制电脑
  16. 你还在为找素材发愁吗?自媒体高手都知道的免费自媒体素材网
  17. Someone Like You 《另寻沧海》
  18. day04 1113 红与黑(flood fill算法,即DFS,BFS)
  19. “三门问题”的理解和Python验证
  20. latch mysql_Latch导致MySQL Crash

热门文章

  1. 树莓派(Raspberry Pi)中如何改变键盘布局(打出~ # | 等符号)
  2. 每日7千次的跨部门任务调度,有赞怎么设计大数据开发平台?
  3. psd转换html字体行高,将PSD网站模板转换为XHTML+CSS
  4. steam战舰世界网站服务器无法使用,Steam上最刚游戏!玩家不套路见面就是干,被称作EVE版战舰世界!...
  5. Redis命令详解:Lists
  6. ORA-00607 Internal error occurred while making a change to a data block处理
  7. 2022-4-10 Leetcode 135.分发糖果
  8. 电脑操作技巧,人人都要知道的电脑技巧
  9. 硕士论文中期汇报ppt_被硕士论文搞崩了心态
  10. 本科函授计算机管理毕业论文,浅谈成人本专科函授生《计算机实用基础》教学,毕业论文 - 论文助手...