文章目录
目录
总结
前言
主要介绍了spring的AOP和循环依赖。
一、AOP
- 基础知识
- 实现AOP的方式
- 动态代理
- Cglib动态字节码
- 自定义类加载器
- AOL扩展
- Java代码生成
- AOP组成
- JoinPoint
可以织入切片逻辑的地方- 方法调用
- 方法调用执行
- 构造方法调用
- 构造方法执行
- 字段设置--setter
- 字段获取--getter
- 异常处理执行
- 类初始化--静态类/块
- Pointcut
指定在哪个joinPoint织入切片逻辑,Pointcut之间可以进行运算- 正则表达式
- 直接指定JoinPoint所在方法名
- 特定Pointcut表述语言
- Advice
具体切入的逻辑的载体--相当于OOP中class里的method- 根据时机
- before Advice--在joinpoint切入点之前执行的Advice
- after Advice--在joinpoint切入点之后执行的Advice
- after returning Advice--正常返回执行
- after throwing Advice--抛出异常执行
- after (Finally) Advice--正常返回&抛出异常都执行
- Around Advice--在joinpoint之前之后都可以执行Advice
- 根据功能
- Introduction
- 根据时机
- Aspect
模块化封装pointcut和Advice--相当于OOP的class - 织入器
将横切关注点逻辑Advice织入到系统- AspectJ---ajc做weaver
- JBoss---自定义类加载器做weaver
- Spring---一组类(ProxyFactory是最通用的)做weaver
- 目标对象
被织入横切逻辑的对象
- JoinPoint
- 实现AOP的方式
- Spring AOP
- 实现机制
- 动态代理&动态字节码生成产生一个代理对象,在代理对象里织入横切逻辑,访问代理对象而非目标对象,实现横切逻辑的扩展
- 静态代理
- 自己去编写代理对象织入切面逻辑,不同目标对象需要写不同的代理对象,但是织入的横切逻却可能相同,重复代码量很大,不推荐使用
- 动态代理--只能用于实现了接口的类
- Proxy类
- 生成动态代理,并且通过InvocationHandler织入切片逻辑
- InvocationHandler接口
- 在接口里写要织入的切片逻辑
- Proxy类
- 动态字节码--直接对类
- Cglib动态生成字节码,创建某个类的子类,通过子类重写父类方法,织入切片逻辑
- Enhancer
- 动态生成子类
- MethodInterceptor
- 扩展了Callback接口,在其实现类里写切片逻辑
- 实现机制
- Spring AOP详解
- joinpoint
- Spring仅支持方法执行级别的joinpoint,对于属性级别可以通过拦截setter、getter方法实现
- pointcut
- classFilter
- class级别的类型匹配,对所有实例对象的类型进行匹配,如果和需要织入切片逻辑的目标对象类型一致,通过matches方法返回true
- MethodMatchers
- matchers(method,targetclass) matchers(method,targetclass,args)
- StaticMethodMatchersPointcut
- matchers(method,targetclass)返回true,isRuntime方法返回false,无需对方法参数进行匹配,比如只需要在方法调用前做一些前置处理的时候,只会用到matchers(method,targetclass)方法
- 一般将该种pointcut的classFilter设置为TRUE,即忽略类型匹配
- DynamicMethodMatchersPointcut
- matchers(method,targetclass)返回true,isRuntime方法返回true,需要对方法参数进行匹配,调用matchers(method,targetclass,args)方法进行深度匹配,适合于需要对方法传入参数做特定处理的情况
- classFilter
- Advice
- per-class---该类型advice写的逻辑可以在目标对象类的所有实例间共享
- BeforeAdvice
- ThrowsAdvice
- AfterReturningAdvice
- 无法对返回值做处理,只能在返回值返回后织入切面逻辑
- AroundAdvice
- 可以补充spring没有提供的AfterAdvice功能,在方法返回时做出一些干预,比如改变返回值
- MethodInterceptor
- 动态生成字节码处搭配Enhancer(生成子类)使用,用于编写切片逻辑
- 可以实现多种类型的Advice,比如AfterAdvice
- per-instance---该类Advice会为 不同实例对象保存各自的状态与相关逻辑
- Introduction是唯一的per-instance类型Advice
- IntroductionIntercepter对目标对象进行拦截,不需要Pointcut(方法级别的拦截),通过接口定义为当前对象添加新的行为
- per-class---该类型advice写的逻辑可以在目标对象类的所有实例间共享
- Aspect(Advisor)
- Spring中的Advisor代表Aspect,每个Advisor拥有一个pointcut和一个Advice,Aspect可以有多个Advice和pointcut
- PointcutAdvisor
- 各种不同的Pointcut对应不同实现类,Advice可以是除了Intruduction之外的任意一个Advice
- IntruductionAdvisor
- Introduction类型的Advice
- 不同的Advisor可以用ordered进行排序
- weaver织入器
- ProxyFactory
- 对于实现了接口的目标对象采用动态代理方式
- 对于没有实现接口或者指定基于类代理的目标对象采用动态字节码
- 继承或间接继承AopProxy和AdvisedSurpport
- 通过AdvisedSupport对生成代理过程所需的相关信息进行配置
- 通过AopProxy实际的去生成代理对象,织入切面逻辑
- 容器中的ProxyFactoryBean
- 生成Proxy的FactoryBean,通过ProxyFactoryBean:pointcut、advice、advisor、目标对象、生成的代理对象全部交给容器管理,只需要将生成的代理对象注入到bean实例对象里,就可以通过访问代理对象,执行切面逻辑,可以将代理对象设置为目标bean的内部bean,防止将目标对象本身注入目标对象bean,导致无法执行切面逻辑
- 自动代理--AutoProxyCreater--beanPostProcessor
- 自己定义ProxyFactoryBean,需要为每个目标对象都手动编写一个ProxyFactoryBean,比较麻烦,通过beanPostProcessor的实现类AutoProxyCreater可以实现自动代理的功能
- BeanNameAutoProxyCreater
- 通过配置信息细化横切逻辑的织入范围,它是一个beanPostProcessor,可以拿到容器里的所有实例对象,对于符合条件的bean实例,通过ProxyFactoryBean创建代理对象
- DefaultAdvisorAutoProxyCreater
- 默认的找到容器里的所有Advisor,通过Advisor中的Pointcut确定需要织入的joinPoint在哪里,并通过ProxyFactoryBean生成代理对象完成Advice的织入
- ProxyFactory
- joinpoint
二、循环依赖
- 定义
- 对象A依赖对象B,对象B依赖对象A,在实例化A的过程中,因为依赖注入会去实例化对象B,在实例化B过程中因为依赖注入又会去实例化对象A,产生循环依赖现象
- 解决方法:三级缓存
- 一级缓存
- 存创建好的完备对象
- 二级缓存
- 存半成品对象
- 三级缓存
- 存lambda表达式,对于需要代理的对象,让代理对象代替目标对象
- 一级缓存
- 解决的过程和原理
- 当我们实例化A对象准备依赖注入B对象,要先把这个创建不完备的半成品A对象放到二级缓存里,然后
- 开始去实例化B对象,我们在实例化B对象时想要为其注入A对象实例
- 我们会先去一级缓存找有没有创建完备的A对象,有则拿到他
- 没有就去二级缓存找有没有正在实例化过程中的A对象,如果有就拿到他
- 然后还应该去三级缓存检查一下A对象需不需要动态代理,如果需要,就执行lambda表达式,让代理对象替换目标对象
- 经过三次查找,可以拿到一个A实例对象,完成B对象的依赖注入,然后将这个创建完备的B对象存到一级缓存里,返回到A对象的实例化过程中
- 这样A对象依赖注入时就可以在一级缓存里拿到B对象实例完成对B对象的依赖注入,然后完成A对象实例化过程,并且将这个创建完备的A对象也放到一级缓存里