AOP技术应用和研究--SpringAop实现原理

        Spring AOP实现遵守了AOP联盟的约定。同时 Spring 又扩展了它,增加了如 PointcutAdvisor 等一些接口使得更加灵活。在SpringAOP模块中,包括AOP的基本概念,通知,切入点等,以及最核心的AopProxy代理对象生成和Spring AOP拦截器调用的实现。

     1,Spring Aop的基本概念

我们在前面 AOP基本概念对AOP基本概念进行了理论上的定义,现在我们将Spring AOP基本概念作为例子来说明AOP的基本概念,这样可以更好的理解AOP基本概念。并且将简单介绍Spring AOP相关的具体实现。

切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。3.3.2中的事务处理类(Transaction)就是一个切面。

连接点(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等等。实际的调用过程就是

目标对象(Target Object):既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。也就是UserDaoImpl target = newUserDaoImpl(); target就是目标对象。

目标对象(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技术应用和研究









郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。