您的位置:首页 > 编程语言 > Java开发

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

2014-09-20 23:39 671 查看
        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技术应用和研究
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息