Spring--AOP&

文章目录

目录

文章目录

前言

一、AOP

二、循环依赖

总结​​​​​​​​​​​​​​


前言

主要介绍了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
      • 目标对象
        被织入横切逻辑的对象
  • Spring AOP
    • 实现机制
      • 动态代理&动态字节码生成产生一个代理对象,在代理对象里织入横切逻辑,访问代理对象而非目标对象,实现横切逻辑的扩展
    • 静态代理
      • 自己去编写代理对象织入切面逻辑,不同目标对象需要写不同的代理对象,但是织入的横切逻却可能相同,重复代码量很大,不推荐使用
    • 动态代理--只能用于实现了接口的类
      • Proxy类
        • 生成动态代理,并且通过InvocationHandler织入切片逻辑
      • InvocationHandler接口
        • 在接口里写要织入的切片逻辑
    • 动态字节码--直接对类
      • 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)方法进行深度匹配,适合于需要对方法传入参数做特定处理的情况
    • Advice
      • per-class---该类型advice写的逻辑可以在目标对象类的所有实例间共享
        • BeforeAdvice
        • ThrowsAdvice
        • AfterReturningAdvice
          • 无法对返回值做处理,只能在返回值返回后织入切面逻辑
        • AroundAdvice
          • 可以补充spring没有提供的AfterAdvice功能,在方法返回时做出一些干预,比如改变返回值
          • MethodInterceptor
            • 动态生成字节码处搭配Enhancer(生成子类)使用,用于编写切片逻辑
            • 可以实现多种类型的Advice,比如AfterAdvice
      • per-instance---该类Advice会为 不同实例对象保存各自的状态与相关逻辑
        • Introduction是唯一的per-instance类型Advice
        • IntroductionIntercepter对目标对象进行拦截,不需要Pointcut(方法级别的拦截),通过接口定义为当前对象添加新的行为
    • 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的织入

二、循环依赖

  • 定义
    • 对象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对象也放到一级缓存里


总结

  Spring是一个框架,也是一种生态,它有两个特性一个是IOC控制反转,一个是AOP面向切片编程,我们一般将会利用Spring的Ioc容器,比如beanFactory或者ApplicationContext实现对受控对象的统一管理。
  通过Ioc容器,我们可以自动创建对象,同时对对象进行依赖注入,Ioc容器使用分为两个阶段,第一阶段是容器初始化,我们会根据配置文件利用BeanDefinitionReader或者通过扫描注解方法创建出所有beanDefinition存到beanDefinitionRegistry中,在容器初始化过程中可以通过beanFactoryPostProcessor去对初始化过程进行扩展,比如扫描注解就是通过其classpathPostProcessor实现类实现;然后进入对象实例化的第二阶段,在这个阶段我们会根据beanDefinition创建实例,配置属性,通过Aware接口向普通对象注入容器对象,然后通过beanPostProcessor机制的before和after Initionlization方法对对象实例化阶段进行扩展,spring的AOP就是通过abtractAutoProxyCreater这个beanPostProcessor实现类完成动态代理的创建实现切面逻辑的织入,然后还有一些init-method和destroy-method可以对对象进行前置处理和销毁;最后还可以通过FactoryBean这个特殊的bean去为容器创建比如动态代理bean或者接口实现类bean;还通过三级缓存解决了spring的循环依赖问题。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值