Spring之AOP



Spring之AOP

本文来介绍Spring的AOP。

 

为什么使用AOP?

使用纯面向对象的思想进行编程。那么对象不但需要处理自身要负责的业务逻辑,要需要关心日志、安全控制和事务。如下图:

图1

 

对遍布系统的关注点服务的调用,经常非常分散。如日志和安全。

 

AOP使这些服务模块化,并以声明的方式将它们应用到它们需要影响的组件中去。结果使这些组件具有高内聚以及更加关注自身业务,完全不需要了解可能涉及的系统服务的复杂性。所以:AOP确保POJO保持简单,AOP是OOP的最好的补充与完善。

利用AOP,我们可以使用各种功能层去包裹核心业务层。这些层以声明的方式灵活应用到你的系统中,甚至你的核心应用根本不知道它们的存在。这是一个非常强大的理念,可以将安全、事务和日志关注点与核心业务分离。如下图:

图2

利用AOP,遍布系统的关注点覆盖在它们所应用的组件之上,促使应用组件只需关注它们的核心业务功能。

 

AOP

AOP有自己术语。尽管这些术语不是很直接,但是我们要逐步了解它们。

 

Cross Cutting Concern横切关注点

横切性关注点,就是要动态执行的方法,它会遍布在系统的处理流程中。

Aspect切面

对横切性关注点的模块化。且面试通知和切点的结合。通知和切点共同定义了关于切面的全部内容——它是什么,在何时何处完成其功能。

Advice通知

对横切性关注点的具体实现。通知定义了切面是什么,以及何时使用。此外,通知还决定了什么时候执行工作的问题。是在应用某个方法被调用之前(Before)、之后(After)、成功执行后(After-returning)、异常(After-throwing)和Around(被通知的方法调用前后)。

 

JoinPoint连接点

Advice在应用程序上执行的点或时机。Spring只支持方法的连接,这个点也可以使属性修改。如Aspectj

连接点是应用执行过程中鞥能够插入切面的一个点。这个店可以使调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。这些操作,都在编译前完成。

Pointcut切点


定义了Advice应用到哪些连接点上,对Spring来说就是方法调用。切面定义了“什么”和“何时”,切点定义了“何处”。切点的定义会匹配同志所有织入的一个或多个连接点。我们通常使用明确的类和方法名称来指定这些切点,或是利用正则匹配类和方法名称模式来指定这些切点。有些AOP框架允许我们动态的切点,可以根据运行时的决策(如方法的参数值)来决定是否应用通知。

Weave织入

将Advice应用到Target Object的过程。Spring支持动态织入。在目标对象的生命周期里多个点可以进行织入:

   编译期——切面在目标类编译时被织入。AspectJ的织入就是这种方式;

   类加载期——切面在目标类加载到JVM时被织入。这种方式需要ClassLoader,可以再目标类被引入应用之前增强目标类的字节码。

   运行期——切面在应用运行的某个时刻被织入。在织入切面时,AOP容器会为目标对象动态创建一个代理对象。这是Spring AOP的织入方式

Proxy

Spring的AOP默认使用JDK的动态代理,它的代理是运行时创建的,也可以使用CGLIB代理。

Introduction

可以动态的为类添加方法。

 

Spring的AOP

目前AOP已经形成了三足鼎立。AspectJ、Jboss AOP和Spring的AOP。这里,我们注重介绍Spring的AOP。Spring只支持方法连接点。应为Spring基于动态代理,所以Spring只支持方法连接点。而AspectJ和JBoss的AOP,除了方法切点,还提供了字段和构造器接入点。Spring缺少对字段连接点的支持。无法让我们创建细粒度的通知。

由于,SpringAOP对方法的支持,就已经足够了。如果还不能满足,可以考虑使用AspectJ来辅助实现。这里,我们重点介绍动态代理方式的AOP。

 

AOP的内部实现

Spring的AOP默认使用JDK的动态代理,同时,也支持CGLIB的代理。

JDK动态代理,采用反射机制动态创建的,动态生成了字节码,只是他生成的字节码的方式必须和接口绑定。

JDK动态代理源码剖析:JDK动态代理实现原理

 

JDK的动态代理有很大限制,这种方法要求业务类必须实现一个业务接口。即,只有下面情况,才能使用JDK的动态代理:

而CGlib引用第三方包asm.jar,采用字节码技术。通过字节码技术为需要代理的类创建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并织入横切逻辑。

CGlib采用继承的方式,继承指定的类,对指定的类生成一个子类。覆盖其所有方法。

这种方式,无论有无接口,都能够对其进行代理,如下面两种情况:

 

CGLIB创建动态代理对象性能比JDK创建的动态代理对象性能高很多,但是CGLIB在创建代理对象时所花费的时间却比JDK多很多。所以对于单例的对象,无需频繁的创建对象,使用CGlib比较合适;则反,如果需要频繁创建对象,考虑使用JDK代理。

 

本文总结了Spring中AOP的相关内容、AOP的相关术语以及内部实现。

具体实现就不往外贴了,比较简单。有兴趣的童鞋可以在下面留言,一起讨论一下。