Spring原理之Aop

一、什么是AOP?

      面向切面编程,简称AOP,AOP是一种特殊的模块化思想,它致力于将分散的、通用的工作进行模块化处理。比如日志、事务、权限控制等,这些功能普遍存在于应用的角角落落,但直接在各处实现,就会导致代码重复、复用性差,变更和维护困难,AOP可以将这些分散的功能从业务核心功能中分离出来,通过模块化实现,在一个地方维护,到处使用, 降低了代码复杂度和耦合度、提高了逻辑独立性、实现软件的高可用性和易维护性等等诸多优点。

      OOP依然是目前软件开发的主导思想,AOP现阶段是在OOP的基础上对软件开发思想的一种补充。

二、目前的AOP技术体系

     下图是AOP联盟定义的AOP体系结构图:

《Spring原理之Aop》

       从图中可以看到,AOP体系分为三个层次:从高到低,分别是语言和开发环境层、面向方面系统层(高层API层)、底层编织实现模块层(底层实现技术层)。

      最高层:语言和开发环境。该层直接面向最终用户,其中的概念:”基础”可以视为AOP服务的目标对象;“切面”可视为对基础的增强应用;“配置”可视为一种编织(使基础和切面可以结合起来,发挥作用的编织实现)。

      中间层:AOP系统层。该层为最高层提供支持,这个层次中可以看到AOP框架的高层实现,比如配置逻辑、编织逻辑以及 

抽象的高层API封装。

      最低层:编织的具体实现层,包含实现编织逻辑的具体技术,比如反射、程序预处理、拦截器框架、类装载器框架、元数据处理等。

三、 Spring AOP

      Spring AOP是Spring提供的AOP实现功能模块,不仅提供了Spring本身的AOP实现,还封装了业界优秀的AOP解决方案AspectJ来供应用使用。

四、Spring AOP的设计与 实现

1、JVM动态代理

       JVM动态代理特性是Spring AOP实现中使用的核心技术。(在JDK 1.3以上的版本里,就实现了动态代理模式 )。通过JDK的动态代理特性,可以为任意Java对象创建代理对象。

       我们先看设计模式中的代理模式:

《Spring原理之Aop》

如图,代理Proxy代理了RealSubject的request方法,Proxy就是RealSubject的代理,代替RealSubject来和Client打交道。

      JDK中实现的就是这种模式,具体的使用方法是,在调用Proxy.newInstance方法生成具体Proxy对象时,把InvocationHandler接口的实现类设置到参数中就可以了,JDK会自己完成在Proxy中调用InvocationHandler接口实现的方法。

        InvocationHandler接口定义如下:

public interface InvocationHandler {
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

其中,动态代理类实现InvocationHandler接口,invoke方法中,proxy为被代理的对象,method为被代理对象的方法,args为传递给该方法的参数列表

参看:http://www.cnblogs.com/xiaoluo501395377/p/3383130.html

2、AOP相关的概念

【】Advice通知

        定义在连接点做什么,为切面增强提供织入接口;在Spring AOP中,它主要描述Spring AOP围绕方法调用而注入的切面行为。比如接口类:BeforeAdvice、AfterAdvice、ThrowsAdvicd等。

【】Pointcut切点

        Pointcut(切点)决定Advice通知应该作用于那个连接点。也就是用Pointcut来标识需要增强的方法。为了方便使用,Spring AOP提供了具体的切点实现,如下:

《Spring原理之Aop》

【】Advisor通知器

        Advisor(通知器)使得切面增强设计(Advice)和关注点设计(Pointcut)结合起来,为使用IoC容器配置AOP应用提供了便利。

3、使用Spring AOP功能

xml配置方式:

      (1)、首先要定义使用的通知器Advisor的Bean。

    (2)、定义ProxyFactoryBean,它是封装AOP功能的主要类,设置与AOP实现相关的属性,比如proxyInterface、interceptorNames和target等;interceptorNames用来指定Advisor的名字(可以是多个)。target用来指定目标类。

      (3)、定义需要应用切面的目标类的Bean,作为target属性注入到ProxyFactoryBean中。

       这样,Spring就可以为target类生成代理对象,并实现对Advisor中的切面功能的应用。

注解方式:

       实现切面,用@Aspect标注,使用@Pointcut标注切点,@Before、@After等标注通知类型,例如:

@Component
@Aspect
public class Audience {

	@Pointcut("execution(* org.spring.aop.Performance.perform())")
	public void perform() {}
	
	@Before("perform()")
	public void silenceCellPhones() {
		System.out.println("Silencing cell phones" );
	}
	
	@Before("perform()")
	public void takeSeats() {
		System.out.println("Taking seats");
	}
	
	@After("perform()") 
	public void applause(){
		System.out.println("CLAP CLAP CLAP");
	}
	
	@After("perform()")
	public void demandRefund() {
		System.out.println("Demanding a refund");
	}
}

完整代码:https://gitee.com/XiaoXiaoYuSheng/spring-test/tree/master/spring-aop 

4、ProxyFactoryBean生成代理对象的过程

       ProxyFactoryBean,顾名思义就是生成代理的FactoryBean, 从FactoryBean中获取对象,是以getObject()方法作为入口的。所以ProxyFactoryBean 需要通过getObject方法来提供一个能够完成AOP功能的代理对象。

      具体的生成过程是在getObject方法中,先初始化通知器链,这时候会读取配置中的所有通知器,为proxy代理对象配置Advisor链。然后根据目标bean的类型是singleton还是prototype,执行getSingletionInstance方法或者newPrototypeInstance方法。 

       这两个方法中会生成AopProxy对象,这个AopProxy对象就是具体的代理对象。AopProxy是一个接口,它由两个子类实现:Cglib2AopProxy、JdkDynamicProxy。分别通过CGLIB和JDK来生成需要的代理对象。如果目标对象是接口类,适合使用JDK自带的动态代理来实现代理,如果目标对象是普通类,适合使用CGLIB的动态字节码技术来实现代理。

     JdkDynamicProxy生成真正的代理对象的方法是使用Jdk的Proxy类,如下:

《Spring原理之Aop》

  Cglib2AopProxy的实现不再分析。

      JdkDynamicProxy、Cglib2AopProxy的getProxy方法都是返回AopProxy对象,这样ProxyFactoryBean的getObject方法得到的对象就是一个AopProxy对象,而不是普通的Java对象,对target目标对象的方法的调用会首先被AopProxy代理对象拦截,如果是JDK生成的AopProxy代理对象,使用的是InvocationHandler的invoke回调入口,而CGLIB的AopProxy代理对象,使用的是设置好的callback回调,也就是DynamicAdvisedInterceptor,它的回调入口是intercept方法。

5 、Spring AOP拦截器调用的实现

    在生成AopProxy对象时,相关的拦截器就已经配置到这个代理对象中了,这仅仅是实现AOP的第一步,真正实现AOP的地方是拦截机制。

   JdkDynamicAopProxy的invoke方法中,会获取目标对象、拦截器链并对拦截器链中的拦截器进行配置,逐个运行拦截器链里的拦截增强。

     CGLIB 实现的AopProxy中的回调是在DynamicAdvisedInterceptor对象中实现的, 在intercept方法中。该方法的实现与JdkDynamicApoProxy的回调实现类似。

       虽然使用JDK和CGLIB会生成不同的AopProxy对象,以及执行不同的拦截器链调用方法,但最终 都殊途同归,对拦截器链的调用都是在ReflectiveMethodInvocation中通过proceed方法实现的。在proceed方法中,会逐个运行 拦截器的拦截方法,在运行拦截器的拦截方法之前,对通过Pointcut切点的matches来匹配代理方法。大体上是通过拦截器进行matches判断,判断是否是适用于横切增强的场合,如果是,从拦截器中得到通知其,并启动通知器的invoke方法进行切面增强,在 这个过程结束后,会迭代调用proceed方法,直到拦截器链中的拦截器都完成以上的拦截过程为止。

       ReflectiveMethodInvocation类的proceed方法中先得到配置的interceptorOrInterceptionAdvice对象,这个对象就是获得的拦截器。取得拦截器链的工作是由配置好的advisorChainFactory来完成的。可以从DefaultAdvisorChainFactory中看到interceptor链的获取过程。DefaultAdvisorChainFactory先获取配置中国interceptNames属性的配置,然后通过AdvisorAdapterRegistry来实现拦截器的注册。有了AdvisorAdapterRegistry注册器,利用它来对从ProxyFactoryBean配置中得到的通知进行适配,从而获得相应的拦截器,再把它加入前面设置好的List中去,完成所谓的拦截器注册过程。在拦截器适配和注册过程完成后,List中的拦截器会被AopProxy代理invoke方法或intercept方法取得,并 启动拦截器的invoke调用,最终触发通知的切面增强。

6、Advice通知的实现

       Spring AOP定义的通知是怎样实现对目标对象的增强的呢?前面提到在DefaultAdvisorChainFactory取得拦截器配置的过程中,有个适配和注册的过程。在DefaultAdvisorChainFactory实现中,首先构造一个GlobalAdvisorAdapterRegistry单例,然后逐个遍历配置的Advisor通知器,然后从registry中获取advisor对应的interceptor数组,然后在加入到拦截器链中。

       GlobalAdvisorAdapterRegistry(是DefaultAdvisorAdapterRegistry的实例)的getInterceptors方法为AOP实现做出了很大的贡献,这个方法封装了advice织入实现的入口。DefaultAdvisorAdapterRegistry中设置了一系列的adapter适配器,这些适配器的实现,为Spring AOP的advice提供编织能力。具体来说,DefaultAdvisorAdapterRegistry会调用adapter的support方法来判断advice属性哪种类型的通知(前置、后置、环绕等),从而来注册不同的AdviceInterceptor。这些AdviceInterceptor都是Spring AOP框架设计好的,比如MethodBeforeAdviceAdapter、AferReturningAdviceAdapter、ThrowsAdviceAdapter等,比如MethodInvocation的invoke回调中,会先触发对advice的before的回调,然后才是MethodInvocation的proceed方法调用。这里可以想到,当AopProxy代理对象触发ReflectiveMethodInvovation的proceed方法时,在取得拦截器以后,启动会拦截器invoke方法的调用,然后如果拦截器是MethodBeforeAdviceAdapter,那么它的invoke方法就会被调用,进而在执行目标方法前执行advice的before方法。

7、使用ProxyFactory实现AOP

     除了可以使用ProxyFactoryBean实现AOP应用之外,还可以使用ProxyFactory来实现Spring AOP的功能。如下:

TargetImpl target = new TargetImpl();
ProxyFactory aopFactory = new ProxyFactory(target);
aopFactory.addAdvisor(yourAdvisor);
aopFactory.addAdvice(yourAdvice);
TargetImpl targetProxy = (TargetImpl)aopFactory.getProxy();

   ProxyFactory取得AopProxy代理对象是以getProxy为入口的,由DefaultAopProxyFactory来完成。原理与通过ProxyFactoryBean方式是一样的。

参看tps://www.cnblogs.com/MOBIN/p/5597215.html

    原文作者:AOP
    原文地址: https://blog.csdn.net/xiaoxiaoyusheng2012/article/details/82858638
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞