文章目录

  • Spring AOP一世
    • Spring AOP的织入
      • 与ProxyFactory打交道
        • 基于接口的代理
        • 基于类的代理
        • Introduction的织入
      • ProxyFactory的本质
      • 容器中的织入器——ProxyFactoryBean
        • ProxyFactoryBean的本质
        • ProxyFactoryBean的使用
      • 加快织入的自动化进程
        • 自动代理得以实现的原理
        • 可用的AutoProxyCreator
        • 扩展AutoProxyCreator
    • TargetSource
      • 可用的TargetSource
      • 自定义TargetSource
    • 小结

Spring AOP一世

Spring AOP的织入

如今,所有基本概念都已经到位,只差将其拼装在一起,也就是织入。还记得我们曾学习过的AOP和OOP在系统实现当中的关系吗?我们需要将AOP织入到OOP中,以便让我们的准备好的一起,行动起来;这个角色就是织入器啦;

Spring AOP采用ProxyFactory类作为织入器;我们就从最基本的织入器开始吧!

所谓织入,就是在Joinpoint(来自OOP业务系统)处加入Advice(来自AOP)所表示的逻辑;

其中Joinpoint由Pointcut进行匹配,于是我们只需要将Pointcut、Advice和业务系统对象交给织入器,然后Magic Happens!织入过程就完成啦;

与ProxyFactory打交道

Pointcut和Advice由Advisor组合;所以我们只要将Advisor和业务对象交给ProxyFactory,然后获得增强版的业务对象(也就是所谓的代理对象)即可;

除了传入Advisor,也可以传入Advice,ProxyFactory将根据传入的Advice创建相应的Advisor,当然,使用的Pointcut为Pointcut.TRUE;

我们可以通过更多的属性设置来控制ProxyFactory的织入行为。Spring通过代理模式实现AOP的时候,采用动态代理和CGLIB两种机制,分别对实现某些接口和未实现接口的目标类生成代理对象;这里所谓的控制,就是控制Spring AOP采用哪种方式进行织入;

基于接口的代理

默认情况下,只要目标对象实现了相应接口,就会对目标对象进行基于接口的代理;我们也可以通过ProxyFactory的setInterfaces()方法指定具体的接口;

需要注意的是,我们可以将代理对象强转为接口类型(也就是通过接口引用代理对象),但是不能将代理对象强转为被代理类,即便它们都实现了相同接口,这也很好理解嘛;

基于类的代理

如果目标对象没有实现任何接口,默认情况下ProxyFactory会对目标类进行基于类的代理,即使用CGLIB;

需要注意的是,即便目标对象也实现了某个接口,我们也可以强制ProxyFactory使用基于类的代理;

总的来说,如果下列条件满足其一,就会使用基于类的代理:

  1. 目标对象没有实现任何接口,此时直接使用基于类的代理;
  2. proxyTargetClass属性为true;
  3. optimize属性为true;

Introduction的织入

Introduction可以为已经存在的对象类型添加新的行为,只能应用于对象级别的拦截,而不是方法级别的拦截;在进行Introduction的织入过程中,不需要指定Pointcut(用于匹配方法),只需指定目标接口类型;

需要注意的是,对Introduction进行织入,新添加的接口类型必须通过setInterfaces指定;原来的目标对象可以自由选择织入方式;

ProxyFactory的本质

知其表而不知其里,充其量也只能算是一个画匠,而不是画师;只懂得如何使用API,而不知道这些API为何如此设计,终将无法迈出从“画匠”到“画师”的那一步;

认清其本质不仅让我们清楚其如何实现,帮助我们获取系统设计的宝贵经验,还可以让我们更加灵活地使用它;

ProxyFactory的根是AopProxy;Spring AOP使用AopProxy对不同的代理实现机制进行了适度的抽象;目前,Spring提供基于JDK的动态代理和CGLIB这两种机制的AopProxy实现:
[外链图片转存失败(img-gVxGmJ4P-1562428071220)(]?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NseDMzMjA2MTI1NDA=,size_16,color_FFFFFF,t_70)

AopProxyFactory通过抽象工厂模式根据传入的AdvisedSupport实例提供的信息,决定创建什么类型的AopProxy:如果isOptimize或者isProxyTargetClass为true,或者目标对象没有实现任何接口,那么就用cglib生成代理对象;否则使用动态代理;

AdvisedSupport实际上就是一个生成代理对象所需信息的载体:

ProxyConfig类记录生成代理对象的控制信息;Advised记录生成代理对象所需要的必要信息,如目标类、Advise、Advisor;

其中,ProxyConfig有以下属性:

  1. proxyTargetClass:默认为false,即使用基于接口的代理;
  2. optimize:该属性为true的时候,proxyFactory将使用CGLIB进行代理;默认为false;实际上,它还指示是否对代理对象进行进一步优化措施;
  3. opaque:控制代理对象是否可以被强转为Advised;默认为false;
  4. exposeProxy:是否将当前代理对象绑定到ThreadLocal,如果目标对象需要访问代理对象,则可以通过AopContext.currentProxy()获得;默认为false;
  5. frozen:如果为true,那么代理对象生成的信息配置完成,那么就不能更改;

到这里,再上一图:

前面我们提到过,ProxyFactory是基本的织入器,那么接下来看看织入器体系以及其他场景下的织入器:

容器中的织入器——ProxyFactoryBean

使用ProxyFactory,我们可以独立使用Spring AOP;所谓独立就是说独立于Spring IoC容器;但是Spring IoC、Spring AOP作为“质量三角”之二,为什么不把它们组合在一起呢?

实际上,合则两利;因为AOP王国里的一切终究是要寄生到OOP王国里的,而Spring IoC 容器对业务对象之间的解耦本领,使得我们构建OOP王国变得简单,那么将Spring AOP同Spring IoC相结合也是“大势所趋”;

Spring IoC 容器内部使用ProxyFactoryBean作为织入器,使用方面同ProxyFactory没有什么大的区别;我们在看清了ProxyFactory的本质之后,自然也要对ProxyFactoryBean一探究竟;

ProxyFactoryBean的本质

ProxyFactoryBean=Proxy+FactoryBean;前者表示其功能为产生Proxy,这是织入器的核心功能;后者表示其本质为FactoryBean;所谓FactoryBean是说,如果容器中的某个对象持有FactoryBean对象引用,那么其获得的不是FactoryBean本身,而是其getObject()方法返回的对象;

FactoryBean创建对象的时候,需要指出其scope:Singleleton或者Prototype;如果是Singleleton的话,FactoryBean就会缓存返回值;

ProxyFactoryBean的使用

同ProxyFactory一样,大部分可以设置的项目都是相同的,因为它们都继承自同一个父类;但是也有一些个性设置:

  1. proxyInterfaces:指定多个接口类型;如果目标对象实现了某个或者多个接口,那么即便我们不显式指定接口,该类也会自动检测,因为有一个属性为autodetectInterfaces,默认值为true;
  2. interceptorNames:指定一组Advisor、Advice或者Interceptor;如果没有通过相应的设置目标对象的方法,明确为ProxyFactoryBean设定目标对象,那么最后一个位置可以放置目标对象;可以使用通配符让ProxyFactoryBean在容器中搜索符合条件的目标对象;
  3. Singleton:属于FactoryBean的属性;

目前为止,AOP中的一切内容都可以在容器中使用啦;从Pointcut到Advice、Advisor;我们可以将生成的代理对象直接注入到需要它的地方;此时,需要注意的是,我们应该依赖代理对象而不是目标对象,否则将不会产生任何拦截效果;

加快织入的自动化进程

在IoC容器中使用ProxyFactoryBean进行织入固然不错,但是如果要对每个目标对象都给出他们各自对应的ProxyFactoryBean配置,太过于麻烦;所以Spring AOP给出了自动代理机制以解决配置工作量较大的问题;

自动代理得以实现的原理

Spring AOP的自动代理依托于ApplicationContext之上,更为准确的说是IoC容器的BeanPostProcessor之上;还记得BeanPostProcessor吗?知识传送门;我们只需要在对象初始化的时候,为其生成代理对象并返回,即可实现织入过程;

所以,所谓织入,其实就是为目标对象生成代理对象的过程;该过程需要织入的内容以及寻找目标对象的方法;

可用的AutoProxyCreator

Spring AOP提供了BeanNameAutoProxyCreator和DefaultAdvisorAutoProxyCreator这两个常用类;

  1. BeanNameAutoProxyCreator:指定一组目标对象的beanName,将一组拦截器应用到这些目标对象之上;在指定BeanName的时候,可使用*通配符;
  2. DefaultAdvisorAutoProxyCreator:如果说BeanNameAutoProxyCreator属于半自动配置的话(毕竟还需要手动指定beanName和拦截器),那么DefaultAdvisorAutoProxyCreator就属于全自动配置了;只需要在容器(ApplicationContext)中声明一个该类的实例,然后只需要描述各种Advisor,容器启动后就会完成织入;

扩展AutoProxyCreator

只需要继承AbstractAutoProxyCreator或者AbstractAdvisorAutoProxyCreator即可,不需要什么都重新开始;

所有的AutoProxyCreator都是InstantiationAwareBeanPostProcessor,这种类型的BeanPostProcessor略有不同;当容器中检测到有该类型的BeanPostProcessor时,会直接通过该类中的逻辑构造对象实例并返回,并不会走正常的对象实例化流程;

所以呢,子类只需要继承合适的父类,然后提供规则匹配一类的逻辑即可;当然,如有必要,进行覆盖即可;

TargetSource

Spring AOP内部会对目标对象做统一的封装——TargetSource。也就是TargetSource代表了调用链终点的目标对象;

它的特性之一就是每次的方法调用都会触发TargetSource的getTarget()方法,getTarget()方法会返回具体的目标对象;

可用的TargetSource

  1. SingletonTargetSource,最为常用的TargetSource实现类;在使用ProxyFactoryBean的setTarget()方法设置完目标对象后,内部处理实际上就是用SingletonTargetSource进行包装;每次方法调用时,都返回同一个目标对象,符合Singleton的语义;
  2. PrototypeTargetSource,符合Prototype的语义,即每次方法调用时都返回新创建的目标对象;此时,目标对象的bean定义声明的Scope必须为prototype;
  3. HotSwappableTargetSource:比较实用的TargetSource实现。它允许我们在系统运行时,根据某种条件动态替换目标对象类的具体实现;通过其swap方法,我们可以使用新的目标对象替换原来的目标对象;
  4. CommonsPoolTargetSource:为目标对象创建一个对象池,然后每次请求对象时,便从对象池中返回;
  5. ThreadLocalTargetSource:将目标对象同线程相关联;不同线程返回不同的目标对象;

自定义TargetSource

直接扩展TargetSource接口即可;

public interface TargetSource extends TargetClassAware {/*** Return the type of targets returned by this {@link TargetSource}.* <p>Can return {@code null}, although certain usages of a {@code TargetSource}* might just work with a predetermined target class.* @return the type of targets returned by this {@link TargetSource}*/@Override@NullableClass<?> getTargetClass();/*** Will all calls to {@link #getTarget()} return the same object?* <p>In that case, there will be no need to invoke {@link #releaseTarget(Object)},* and the AOP framework can cache the return value of {@link #getTarget()}.* @return {@code true} if the target is immutable* @see #getTarget*/boolean isStatic();/*** Return a target instance. Invoked immediately before the* AOP framework calls the "target" of an AOP method invocation.* @return the target object which contains the joinpoint,* or {@code null} if there is no actual target instance* @throws Exception if the target object can't be resolved*/@NullableObject getTarget() throws Exception;/*** Release the given target object obtained from the* {@link #getTarget()} method, if any.* @param target object obtained from a call to {@link #getTarget()}* @throws Exception if the object can't be released*/void releaseTarget(Object target) throws Exception;}

小结

这一节中,我们了解了Spring AOP对AOP的各种概念的实现;它们是整个框架的基础;体现了Spring框架的稳定性和灵活性;

接下来,我们将看看Spring AOP一世的升级版——Spring AOP 二世;

Spring 揭秘之Spring AOP一世(2)织入实现相关推荐

  1. 有关AOP术语(织入、增强等)的个人理解

    2021.4.11 阅读<精通Spring4.x企业应用开发实战>一书做笔记 下图为本人理解的AOP术语韦恩图,由于引介跟增强在同一个位置,没在图上标出. 连接点(Joint Point) ...

  2. 《Spring揭秘》读书笔记 2:Spring AOP

    7 一起来看AOP 2009年8月,<一起来看流星雨>开播. 2009年9月,<Spring揭秘>出版. 7.1 AOP核心概念 AOP AOP全称为Aspect-Orient ...

  3. 从Spring源码探究AOP代码织入的过程

    随着不断地使用Spring,以及后续的Boot.cloud,不断的体会到这个拯救Java的生态体系的强大,也使我对于这个框架有了极大的好奇心,以至于产生了我为什么不能写一个这样的框架的思考. 通过自学 ...

  4. 专治不会看源码的毛病--spring源码解析AOP篇(2017版)

    昨天有个大牛说我啰嗦,眼光比较细碎,看不到重点.太他爷爷的有道理了!要说看人品,还是女孩子强一些.原来记得看到一个男孩子的抱怨,说怎么两人刚刚开始在一起,女孩子在心里就已经和他过完了一辈子.哥哥们,不 ...

  5. spring的aop配置-配置将通知织入目标对象

    咱们学习如何来进行配置,再新建一个包,d_springaop,然后配置文件需要单独在aop中配置一份,在这里面咱们来看一下,如何进行配置,首先在配置之前要有一个准备工作,咱们要用到新的名称空间了,又要 ...

  6. 说说在 Spring AOP 中如何实现类加载期织入(LTW)

    我们可以在类加载期通过字节码编辑技术将切面织入目标类,这种方式叫做 LTW(Load Time Weaving). AspectJ LTW 使用 Java 5.0 提供的代理功能实现织入工作 .JDK ...

  7. Java手写Spring的AOP(切面织入)小Demo--盲僧代理击飞 亚索接大实例

    在学习Spring的过程中总会很迷茫,打个@Aspect注解切面功能就有了,只要脱离了框架感觉自己还是什么都没会,所以自己猜了一下切面的思路,大概写了个小Demo,欢迎交流. 涉及知识:JDK动态代理 ...

  8. Spring框架系列之AOP思想

    微信公众号:compassblog 欢迎关注.转发,互相学习,共同进步! 有任何问题,请后台留言联系! 1.AOP概述 (1).什么是 AOP AOP 为 Aspect Oriented Progra ...

  9. Spring思维导图,让Spring不再难懂(aop篇)

    2019独角兽企业重金招聘Python工程师标准>>> 什么是aop AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Or ...

最新文章

  1. linux 查找清理大文件
  2. TensorFlow学习笔记(二十三)四种Cross Entropy交叉熵算法实现和应用
  3. 图片缓存之内存缓存技术LruCache,软引用
  4. 汇编语言典型例子详解_数据分析常用的7大思维方法详解
  5. 实战生产环境:kubeadmin安装1.13.3最新版k8s集群教程
  6. Java课程设计基于ssm的微信小程序
  7. Windows Terminal 已上架,快尝鲜
  8. 为什么很多人只提苹果手机比安卓手机流畅耐用,却不提苹果手机比安卓手机贵几倍?
  9. STM32 AES 加解密流程梳理
  10. 战神z7完美linux,不黑不吹 战神Z7游戏本的质量真的差么?
  11. 自动驾驶-MPC控制器
  12. 网易邮箱大师添加附件显示服务器连接失败,网易邮箱大师如何添加Word附件 添加附件方法步骤详细介绍...
  13. 国内各大安卓市场有ASO优化吗?安卓应用市场aso优化
  14. 分享抖音上热门技巧!短视频涨粉+运营攻略!
  15. CAD中怎么在线缆上输入或删除文字?
  16. 关于AXD调试的详细探索
  17. AutoCAD启动缓慢
  18. 进程间的相互通讯 C++
  19. easyui datagrid editor 编辑器的简单活用以及自定义校验
  20. 基于51单片机的红外报警实验

热门文章

  1. 黑幕!!!威客网站七宗罪?一个威客的自诉
  2. 树莓派远程视频监控的移植pistreaming
  3. 滴滴青桔单车跨端技术方案和业务技术架构,及框架设计和性能提升实践
  4. Linux(CentOS)下安装NVIDIA GPU驱动
  5. 美股 基础知识2-常见问答
  6. Elasticsearch实战 | match_phrase搜不出来,怎么办?
  7. 无人机作业||by 郑,蒋
  8. Hive 数据聚合成键值对时,根据值大小进行排序
  9. 从iQOOZ1到iQOOZ1x,iQOO何以能持续打造爆款?
  10. m118w重置墨粉_打印机M118W墨粉盒如何清零