读书笔记-《Spring技术内幕》(二)AOP的实现

前面我们已经学习了 IoC(读书笔记-《Spring技术内幕》(一)IoC容器的实现),相比之下,Spring AOP 部分没有那么多的类层次设计,但是出现了许多相关的知识点,我们先复习一下,以便后文阅读流畅。


01

知识点复习

1.代理模式

上图为代理模式的类图。简单来说,其他对象无法直接访问 RealSubject,而是通过访问 Proxy 来间接访问 RealSubject。

基于代理类的创建方式和使用场景,又分为了静态代理模式和动态代理模式。前者是在编译时预先写好代理类的代码,而后者是在运行时动态生成的。

2.反射

即程序可以访问、检测和修改它本身状态或行为的一种能力。

前面提到的动态代理模式,其代理类就可以通过反射来实现。

3.回调函数

严格意义上讲,是把一个函数当作参数时,这个函数就是回调函数。也就是说这个函数应该是通过指针调用的。

function callback() {
    ...
}
function hello(func) {
    ... 
}
hello(callback);

不过实际情况中,大家会把使用到回调思想的异步处理函数也称为回调函数,不必过于纠结。

// Team A
function hello() {
    world()
    ...
}
function callback() {
    ...
}

// Team B
function world() {
    ...
    callback()
}


02

引出问题

在软件工程的发展中,开发者在不断优化开发流程、提高软件质量。

面向过程编程(POP时,通过模块划分将函数进行封装,增加可维护性。面向对象编程(OOP)时,通过各种设计模式使得程序设计更加优雅。

但有一类代码(例如统计接口的耗时、日志、操作记录等),不方便使用继承来进行管理,即使封装成公共函数,在每处都显示调用也会造成特别多的重复代码。针对这个问题,面向切面编程(AOP)的思想就出现了。

如图所示,我们需要找到一个办法,让这条横线的功能仅使用一处代码实现,这样不会造成重复代码,业务代码与非业务代码也不耦合,就很优雅了。

答案之一便是前面复习的动态代理模式,当然,既然提出了 AOP,那大佬们必然也会给出更多的定义,就像 OOP 的封装、继承、多态一样。


03

关于AOP

我们结合上图,来看下 AOP 的相关定义。

  • 切面(Aspect):可以理解为上图中横向的绿色箭头。

  • 连接点(Joinpoint):被切面划开的点,例如上图业务代码的执行前和执行后。

  • 通知(Advice):在连接点执行的代码,例如上图的打印参数、记录耗时。

  • 切点(Pointcut):用于定义哪些连接点上应该通知,相当于是连接点的子集。

  • 织入(Weaving):指将切面应用到目标对象并创建新的代理对象的过程。

下图为 AOP 联盟定义的 AOP 体系结构,从上至下是开发语言层面到底层实现。以 Spring AOP 为例,我们只需要学习语言和开发环境这个层面,使用Spring 定义好的注解,编写相关代码并做好配置,就可以实现我们上图右侧想要的效果。但更深入的话还可以了解它的配置模型,以及底层是基于什么实现的。


04

Spring AOP 设计与实现

1.设计原理

以 ProxyFactory 为设计中心,类图如下:

简单概括一下:

  • ProxyConfig:可看作一个数据基类,为子类提供配置属性。

  • AdvisedSupport:封装 AOP 对通知和通知器的相关操作。

  • ProxyCreatorSupport:创建 AOP 代理对象的一个辅助类。

  • AspectJProxyFactory:对于使用 AspectJ 的 AOP 应用,起到集成 Spring 和 AspectJ 的作用,并生成 AOP 代理对象。

  • ProxyFactoryBean:对于使用 Spring AOP 的应用,生成 AOP 代理对象。(可在 IoC 容器中完成声明式配置)

  • ProxyFactory:对于使用 Spring AOP 的应用,生成 AOP 代理对象。(需要编程式使用)

2.以 ProxyFactoryBean 为例,代理对象的生成与使用

首先ProxyFactoryBean 生成 AopProxy 过程如下:

  • ProxyFactoryBean.initializeAdvisorChain()

  • ProxyFactoryBean.getSingletonInstance()

  • ProxyCreatorSupport.getPaoxy()

  • DefaultAopProxyFactory.createAopProxy()

  • JdkDynamicAopProxy() 或 CglibProxyFactory.createCglibProxy()

在 DefaultAopProxyFactory.createAopProxy() 中,我们可以看到两种动态代理的区别之一,是 JDK 动态代理适用于实现了接口的类。

if (targetClass.isInterface()) {
    return new JdkDynamicAopProxy(config);
}
if (!cglibAvailable) {
    throw new AopConfigException("没找到CGLIGB配置")
}
return CglibProxyFactory.createCglibProxy(config);

再往下走,就是 :

// 在 JdkDynamicAopProxy.getProxy() 中
Proxy.newProxyInstance();

// 在 Cglib2AopProxy.getProxy() 中
proxy = enhancer.create();

两者主要区别在于,JDK 是通过反射实现,CGLIB 通过字节码实现,基于此,两者的使用条件、创建代理速度、运行时速度、应用场景自然就各有优劣了。

其次在得到 AopProxy 对象后,当代理的接口方法被调用执行时, Proxy 机制就开始干活了。它会触发对这些方法的拦截。

具体来说,这是一个遍历定义好的拦截器的过程,经过这些拦截,我们的对象就得到了增强。拦截器在前面代理对象生成时便已经缓存好了,以拦截器生成的视角来看,流程如下:

  • ProxyFactoryBean.getObject() 对 advisor 进行初始化,从 XML 配置中获取 advisor 通知器。

  • DefaultAdvisorChainFactory 直接从 config 中获取 advisor 链。

  • DefaultAdvisorChainFactory 通过 AdvisorAdapterRegistry 注册拦截器链。

  • AdvisedSupport 通过 DefaultAdvisorChainFactory 获取拦截器链并缓存到 List。

  • ReflectiveMethodInvocation.proceed() 从 interceptorsAndDynamicMethodMatchers (即上面的 List) 中获得拦截器。

  • 基于JDK 动态代理中:JdkDynamicAopProxy.invoke() 调用 ReflectiveMethodInvocation.proceed() 。

  • 基于 CGLIB 动态代理中:DynamicAdvisedInterceptor.intercept() 调用 ReflectiveMethodInvocation.proceed() 。

3.ProxyFactory 生成 AopProxy

也可以试试编程式使用,这样步骤看着更加清晰简单,说白了也就是把 advisor 和 advice 准备好,然后生成代理对象再使用的过程。

TargetImpl target = new TargetImpl();
ProxyFactory aopFactory = new ProxyFactory(target);
aopFactory.addAdvisor(myAdvisor);
aopFactory.addAdvice(myAdvice);
TargetImpl targetProxy = (TargetImpl)aopFactory.getProxy();

至此,我们以 ProxyFactoryBean 和 ProxyFactory 为例学习了 Spring AOP 的实现。感兴趣的话还可以了解下 Spring AOP 的高级特性或是其他 AOP 解决方案如 AspectJ,不过考虑到实际业务需求以及学习成本,Spring AOP 基本功能是完全够用的。


原文链接:读书笔记-《Spring技术内幕》(二)AOP的实现

原创不易,点个关注不迷路哟,谢谢!

文章推荐:

  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值