AOP技术应用和研究--SpringAop实现原理
Spring 的AOP实现遵守了AOP联盟的约定。同时 Spring 又扩展了它,增加了如 Pointcut、Advisor 等一些接口使得更加灵活。在Spring的AOP模块中,包括AOP的基本概念,通知,切入点等,以及最核心的AopProxy代理对象生成和Spring AOP拦截器调用的实现。
1,Spring Aop的基本概念
我们在前面 AOP基本概念对AOP基本概念进行了理论上的定义,现在我们将Spring AOP基本概念作为例子来说明AOP的基本概念,这样可以更好的理解AOP基本概念。并且将简单介绍Spring AOP相关的具体实现。
l 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。3.3.2中的事务处理类(Transaction)就是一个切面。
l 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。3.3.2中proxy.updatePerson();就是连接点
l 通知(Advice):定义在连接点做什么,为切面增强提供织入接口。在上面动态代理的例子中切面Transaction的方法beginTransaction()和commit()分别是前置通知和后置通知。其实在这里通知就是切面中的方法。在Spring AOP中,它主要描述Spring AOP围绕方法调用而注入的切面行为。Advice 是AOP联盟定义的一个接口,具体的接口定义在org.aopalliance.aop.Advice中。在Spring AOP的实现中,使用了这个统一的接口,并通过这个接口,为AOP切面增强的织入功能做了更多的细化和扩展,比如提供了更具体的通知类型,如BeforeAdvice,AfterAdvice,ThrowsAdvice等。
作为Spring AOP定义的接口类,具体的切面增强可以通过这些接口集成到AOP框架中去发挥作用。对于这些接口类,我们将以BeforeAdvice为例来说明。首先了解它的类层次关系,如图3.8, BeforeAdvice类层次图
在BeforeAdvice的继承关系中,定义了为待增强的目标方法设置的前置通知的接口MethodBeforeAdvice,使用这个前置接口需要实现一个回调函数:void before(Method method, Object[] args, Object target) throwsThrowable作为回调函数,before()方法的实现在Advice中被配置到目标方法后,会在目标方法时被回调。具体的调用参数有Mehod对象,这个参数是目标方法的反射对象;Object[]对象数组,这个对象数组中包括目标对象方法的输入参数。
切入点(Pointcut):决定Advice通知应该作用于哪个连接点。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。在动态代理中if("saveUser".equals(methodName)||"updateUser".equals(methodName)||……)就是切入点。当方法名为符合切入点saveUser,updateUser时就执行相应的通知。Spring AOP提供了具体的切点供用户使用,切入点在Spring AOP类继承体系如图3.9所示:
在Spring AOP如有针对注解配置的AnnotationMatchingPointcut、针对正则表达式的JdkRegexpMethodPointcut等等。实际的调用过程就是
l 目标对象(Target Object):既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。也就是UserDaoImpl target = newUserDaoImpl(); target就是目标对象。
l 目标对象(Target Object):既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。也就是UserDaoImpl target = newUserDaoImpl(); target就是目标对象。
l AOP代理(AOP Proxy):在Spring AOP中,AOP代理可以是JDK动态代理或者CGLIB代理。3.3.2中示例中proxy就是代理对象。我们容易发现代理对象的方法=目标对象的目标方法+通知。
l 织入(Weaving):SpringAOP和其他纯Java AOP框架一样,在运行时完成织入。织入其实就是形成代理的方法的过程。
l 通知器(Advisor):Advisor属于Spring AOP扩展的内容。Advisor完成对目标方法的通知(Advice)和切入点(Pointcut)设计以后,需要一个对象将它们结合起来,完成这个作用的就是Advisor。通过Advisor,可以定义应该使用哪个通知并在哪个关注点使用它,也就是说通过Advisor,把Advice和Pointcut结合起来,这个结合为使用IoC容器配置AOP应用。在Spring AOP中,Advisor的实现类都有两个属性,分别为advice和pointcut。通过这两个属性,可以分别配置Advice和Pointcut。
2,生成代理对象
由上文中动态代理中可以知道AOP首要任务就是生成代理对象,对于Spring的应用,可以看到,是通过配置和调用Spring的ProxyFactoryBean来完成这个任务的。在这个生成过程中,可以使用JDK的Proxy和cglib两种方式生成。
以ProxyFactory的设计中心,可以看到相关的类继承关系如图3.10所示:
分析Spring AOP的底层实现首先要从ProxyConfig类开始,ProxyConfig是所有产生Spring AOP代理对象的基类,它是一个数据类,主要为其AOP代理对象工厂实现类提供配置属性。根据ProxyConfig的继承体系分析创建AOP代理常用类的作用:
l AdvisedSupport是ProxyConfig的子类,它封装了AOP中对通知(Advice)和通知器(Advisor)的相关操作,这些操作对于不同的AOP的代理对象的生成都是一样的,但对于具体的AOP代理对象的创建,AdvisedSupport把它交给子类去实现。
l ProxyCreatorSupport是AdvisedSupport的子类,它是其子类创建AOP代理对象的一个辅助类,提供不同AOP代理对象生成的通用操作,具体的AOP代理对象生成,由ProxyCreatorSupport的子类完成。
l 创建AOP代理对象的类:
ProxyCreatorSupport有3个子类,分别创建不同的AOP代理对象,具体如下:
AspectJProxyFactory:主要用于创建AspectJ的AOP应用,起到集成Spring和AspectJ的作用。ProxyFactory:创建编程式的Spring AOP应用。
ProxyFactoryBean:创建声明式的Spring AOP应用。
由于ProxyFactoryBean是在Spring IoC环境中创建AOP应用的底层方法,也是最灵活的方法,Spring通过它完成了对AOP使用的封装。将在下文以ProxyFactoryBean的实现为入口介绍AopProxy代理对象的实现。
在ProxyFactoryBean中,通过target目标对象生成Proxy代理对象,从而为AOP横切面的编织工作做好准备工作。具体的代理对象生成工作是通过jdk的Proxy或cglib来完成的。具体的AopProxy生成过程如图3.11所示:
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware { //标注通知器器为全局通用通知器 public static final String GLOBAL_SUFFIX = "*"; //标志通知器链是否已经完成初始化 private boolean advisorChainInitialized = false; //单态模式对象 private Object singletonInstance; …… //ProxyFactoryBean创建AOPProxy代理的入口方法 public Object getObject() throws BeansException { //初始化通知器链 initializeAdvisorChain(); //如果目标对象是单态模式 if (isSingleton()) { //调用获取单态模式对象的方法产生AOPProxy代理 return getSingletonInstance(); } //如果目标对象是原型模式 else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } //调用原型模式对象方法每次创建一个新的AOPProxy代理对象 return newPrototypeInstance(); } }
通过源码分析,我们了解到ProxyFactoryBean实现了FactoryBean接口,所以本身也是一个Spring的工厂Bean,AOP代理工厂的主要功能概况为:
a.初始化通知器链,将配置的通知器链添加到容器存放通知/通知器的集合中。
b.根据单态模式/原型模式,获取AopProxy产生AopProxy代理对象。
如下是ProxyFactoryBean的getSingletonInstance()方法的源代码:private synchronized Object getSingletonInstance() { if (this.singletonInstance == null) { …//省略 this.singletonInstance = getProxy(createAopProxy()); } return this.singletonInstance; } 红色部分getProxy()的源代码: protected Object getProxy(AopProxy aopProxy) { return aopProxy.getProxy(this.proxyClassLoader); }
由上面可知ProxyFactoryBean是通过createAopProxy()方法创建的AopProxy对象来创建AopProxy代理对象(AopProxy对象和AopProxy代理对象不是同一个概念,AopProxy代理对象是由AopProxy对象创建的,AopProxy是一个接口,声明了了创建AopProxy代理对象的方法getProxy())。在ProxyFactoryBean的getObjet的getSingletonInstance()和newPrototypeInstance()方法均通过调用ProxyCreatorSupport的createAopProxy()方法获取AopProxy对象(ProxyFactoryBean通过继承ProxyCreatorSupport来获得了createAopProxy()方法),ProxyCreatorSupport的createAopProxy()方法的源码如下:
protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); }如上面的源代码所示,这里使用的了AopProxyFactory来创建AopProxy对象。
public AopProxyFactory getAopProxyFactory() { return this.aopProxyFactory; } public ProxyCreatorSupport() { this.aopProxyFactory = new DefaultAopProxyFactory(); }显然这个AopProxyFactory是DefaultAopProxyFactory。下面我们看DefaultAopProxyFactory是如何生成AopProxy代理对象即可。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { …//非核心部分省略 //如果配置的AOP目标类是接口,则使用JDK动态代理机制来生成AOP代理 if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } //如果AOP配置的目标类不是接口,则使用CGLIB的方式来生成AOP代理 if (!cglibAvailable) { throw new AopCongifgException( "Cannot proxy target class because CGLIB2 is not available. " + "Add CGLIB to the class path or specify proxy interfaces."); } return CglibProxyFactory.createCglibProxy(config); } else { //默认生成的是JdkDynamicAopProxy对象 return new JdkDynamicAopProxy(config); } }
我们通过上面的分析知道AopProxy代理对象是由AopProxy对象生成,AopProxy代理对象可以由jdk或cglib来生成,而JdkDynamicAopProxy和Cglib2AopProxy实现的都是AopProxy接口,如图3.12。其中jdk对应JdkDynamicAopProxy,cglib对应Cglib2AopProxy。
jdk生成AopProxy代理对象
JdkDynamicAopProxy生成代理对象过程的代理清单如下: public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
显然它是调用Proxy的newProxyInstance()方法来生成AopProxy代理对象,
由前面jdk动态代理可知,这就是使用的jdk动态代理。而Proxy在生成代理对象时,需要指明三个参数,一个是类加载器,一个是代理接口,另外一个是Proxy回调方法所在的对象,这个对象需要实现InvocationHandler接口。而JdkDynamicAopProxy本身实现了InvocationHandler接口和invoke()方法。这就是Spring AOP利用jdk动态代理生成AopProxy代理对象的整个过程。cglib生成AopProxy代理对象
jdk的动态代理只能针对接口生成代理对象,对于没有实现接口的目标对象,必须通过第3方的CGLIB来生成代理对象,CglibProxyFactory创建AopProxy代理的主要源码如下: //通过CGLIB方式创建AOP代理对象 public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating CGLIB2 proxy: target source is " + this.advised.getTargetSource()); } try { //从代理创建辅助类中获取在IoC容器中配置的目标对象 Class rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); //将目标对象本身做为自己的基类 Class proxySuperClass = rootClass; //检查获取到的目标类是否是CGLIB产生的 if (AopUtils.isCglibProxyClass(rootClass)) { //如果目标类是有CGLIB产生的,获取目标类的基类 proxySuperClass = rootClass.getSuperclass(); //获取目标类的接口 Class[] additionalInterfaces = rootClass.getInterfaces(); //将目标类的接口添加到容器AOP代理创建辅助类的配置中 for (Class additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } //校验代理基类 validateClassIfNecessary(proxySuperClass); //配置CGLIB的Enhancer类,Enhancer是CGLIB中的主要操作类 Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } //设置enhancer的基类 enhancer.setSuperclass(proxySuperClass); enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class)); //设置enhancer的接口 enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setInterceptDuringConstruction(false); //设置enhancer的回调方法 Callback[] callbacks = getCallbacks(rootClass); enhancer.setCallbacks(callbacks); //将通知器中配置作为enhancer的方法过滤 enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); Class[] types = new Class[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } //设置enhancer的回调类型 enhancer.setCallbackTypes(types); //创建代理对象 Object proxy; if (this.constructorArgs != null) { proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs); } else { proxy = enhancer.create(); } return proxy; } catch (CodeGenerationException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of class [" + this.advised.getTargetClass() + "]: " + "Common causes of this problem include using a final class or a non-visible class", ex); } catch (Exception ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } } //获取给定类的回调通知 private Callback[] getCallbacks(Class rootClass) throws Exception { //优化参数 boolean exposeProxy = this.advised.isExposeProxy(); boolean isFrozen = this.advised.isFrozen(); boolean isStatic = this.advised.getTargetSource().isStatic(); //根据AOP配置创建一个动态通知拦截器,CGLIB创建的动态代理会自动调用 //DynamicAdvisedInterceptor类的intercept方法对目标对象进行拦截处理 Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised); Callback targetInterceptor; //根据是否暴露代理,创建直接应用目标的通知 if (exposeProxy) { targetInterceptor = isStatic ? new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) : new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()); } else { targetInterceptor = isStatic ? new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) : new DynamicUnadvisedInterceptor(this.advised.getTargetSource()); } // 创建目标分发器 Callback targetDispatcher = isStatic ? new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp(); Callback[] mainCallbacks = new Callback[]{ aopInterceptor, //普通通知 targetInterceptor, // 如果优化则不考虑配置的通知 new SerializableNoOp(), //没有被覆盖的方法 targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised), new HashCodeInterceptor(this.advised) }; Callback[] callbacks; //如果目标是静态的,并且通知链被冻结,则使用优化AOP调用,直接对方法使用 //固定的通知链 if (isStatic && isFrozen) { Method[] methods = rootClass.getMethods(); Callback[] fixedCallbacks = new Callback[methods.length]; this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length); for (int x = 0; x < methods.length; x++) { List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass); fixedCallbacks[x] = new FixedChainStaticTargetInterceptor( chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass()); this.fixedInterceptorMap.put(methods[x].toString(), x); } //将固定回调和主要回调拷贝到回调数组中 callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length]; System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length); System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length); this.fixedInterceptorOffset = mainCallbacks.length; } //如果目标不是静态的,或者通知链不被冻结,则使用AOP主要的通知 else { callbacks = mainCallbacks; } return callbacks; }
从上面的代码清单我们可以看到具体的cglib的使用,比如Enhancer对象的配置,以及Enhancer对象生成代理对象的过程。在这个生成代理对象的过程中,需要注意的是Enhancer对象callback回调的设置,正是这些回调封装了Spring AOP的实现,就像前面介绍jdkproxy对象的invoke回调方法一样。在Enhancer的callback回调设置中,实际上是通过设置DynamicAdvisedInterceptor拦截器来完成AOP功能的。我们可以再getCallBacks()方法中看到回调DynamicAdvisedInterceptor的设置。
CallBack aopInterceptor =new DynamicAdvisedInterceptor(this.advised);
DynamicAdvisedInterceptor实现了MethodInterceptor类。这样通过AopProxy对象封装target目标对象之后,ProxyFactoryBean的getObject()方法得到对象就不是一个普通的对象了,而是一个AopProxy代理对象。在ProxyFactoryBean配置的target目标对象,这时已经不会让应用直接调用其方法实现,而是作为AOP实现的一部分。对target目标对象的方法调用会首先被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。例如,对于jdk的AopProxy代理对象,使用的是InvocationHandler的invoke回调入口;而对于cglib的AopProxy代理对象,使用的是设置好的callback回调,这是有对cglib的使用来决定的。在这些callback回调中,对于AOP实现,是通过DynamicAdvisedInterceptor来完成的。而DynamicAdvisedInterceptor的回调入口是intecepr()方法。通过这一系列的准备,已经为实现AOP横切机制尊定了基础,在这个基础上,AOP的advisor已经可以通过AopProxy代理对象的拦截机制,对需要它进行增强的target目标对象发挥切面的强大威力了。
3,Spring AOP拦截器调用的实现
DynamicAdvisedInterceptor来完成回调。关于两种方式的拦截过程,下面将进行详细分析。
3.1, JdkDynamicAopProxy的invoke拦截
我们回顾下JdkDynamicAopProxy中生成Proxy对象时,是newProxyInstance(classLoader,proxiedInterface,this);这里的this参数对应的是InvocationHandler对象,InvocationHandler是jdk定义的反射类的一个接口。在JdkDynamicAopProxy中实现了InvocationHandler接口,也就是说当Proxy对象代理方法被调用时,JdkDynamicAopProxy的invoke方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,来完成对目标对象方法调用的拦截的工作。JdkDynamicAopProxy的invoke完成了对Proxy对象的设置,这些设置包括获取目标对象,拦截器链,同时把这些对象作为输入,创建ReflectiveMethodInvocation对象,通过ReflectiveMethodInvocation对象完成对AOP功能实现的封装。具体运行的时序图:
3.2 Cglib2AopProxy的intercept拦截
在分析Cglib2AopProxy的AopProxy代理对象生成的时候,我们了解到对于AOP的拦截调用,其回调是在DynamicAdvisedInterceptor对象中实现,这个回调的实现在intercept方法中。Cglib2AopProxy的intercept回调方法的实现和JdkDynamicAopProxy的回调实现是非常相似的,只是Cglib2AopProxy中构造CglibMethodInvocation对象来完成拦截器链的调用,而在JdkDynamicAopProxy中是通过ReflectiveMethodInvocation对象完成这个功能的。AOP技术应用和研究系列博客 AOP技术应用和研究
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。