Spring源代码解析(五):SpringAOP获取Proxy

下面我们来看看Spring的AOP的一些相关代码是怎么得到Proxy的,让我们我们先看看 AOP和Spring AOP的一些基本概念:

Advice:

通知,制定在连接点做什么,在Sping中,他主要描述Spring围绕方法调用注入的额外 的行为,Spring提供的通知类型有:

before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,这些都是 Spring AOP定义的接口类,具体的动作实现需要用户程序来完成。

Pointcut:

切点,其决定一个advice应该应用于哪个连接点,也就是需要插入额外处理的地方的 集合,例如,被某个advice作为目标的一组方法。Spring pointcut通常意味着标示方法 ,可以选择一组方法调用作为pointcut,Spring提供了具体的切点来给用户使用,比如正 则表达式切点 JdkRegexpMethodPointcut通过正则表达式对方法名进行匹配,其通过使用 AbstractJdkRegexpMethodPointcut中的对MethodMatcher接口的实现来完成pointcut功能 :

Java代码

public final boolean matches(Method method, Class targetClass) {     //这里通过放射得到方法的全名     String patt = method.getDeclaringClass().getName() + "." + method.getName();     for (int i = 0; i < this.patterns.length; i++) {       // 这里是判断是否和方法名是否匹配的代码       boolean matched = matches(patt, i);       if (matched) {         for (int j = 0; j < this.excludedPatterns.length; j++) {           boolean excluded = matchesExclusion(patt, j);           if(excluded) {             return false;           }         }         return true;       }     }     return false;   }

在JDKRegexpMethodPointcut中通过JDK中的正则表达式匹配来完成pointcut的最终确 定:

Java代码

protected boolean matches(String pattern, int patternIndex) {     Matcher matcher = this.compiledPatterns[patternIndex].matcher (pattern);     return matcher.matches();   }

Advisor:

当我们完成额外的动作设计(advice)和额外动作插入点的设计(pointcut)以后,我们 需要一个对象把他们结合起来,这就是通知器 – advisor,定义应该在哪里应用哪个通知 。Advisor的实现有:DefaultPointcutAdvisor他有两个属性advice和 pointcut来让我们 配置advice和pointcut。

接着我们就可以通过ProxyFacToryBean来配置我们的代理对象和方面行为,在 ProxyFacToryBean中有intercepTorNames来配置已经定义好的通知器-advisor,虽然这里 的名字叫做interceptNames,但实际上是供我们配置advisor的地方,具体的代理实现通过 JDK 的Proxy或者CGLIB来完成。因为ProxyFacToryBean是一个FacToryBean,在 ProxyFacToryBean中我们通过getObject()可以直接得到代理对象:

Java代码

public Object getObject() throws BeansException {     //这里初始化通知器链     initializeAdvisorChain();     if (isSingleton()) {     //根据定义需要生成单件的Proxy       return getSingletonInstance();     }     else {     .......       //这里根据定义需要生成Prototype类型的Proxy       return newPrototypeInstance();     }   }

我们看看怎样生成单件的代理对象:

Java代码

private synchronized Object getSingletonInstance() {     if (this.singletonInstance == null) {       this.targetSource = freshTargetSource();       if (this.autodetectInterfaces && getProxiedInterfaces ().length == 0 && !isProxyTargetClass()) {         // 这里设置代理对象的接口         setInterfaces(ClassUtils.getAllInterfacesForClass (this.targetSource.getTargetClass()));       }       // Eagerly initialize the shared singleton instance.       super.setFrozen(this.freezeProxy);       // 注意这里的方法会使用ProxyFacTory来生成我们需要的Proxy       this.singletonInstance = getProxy(createAopProxy());       // We must listen to superclass advice change events to recache the singleton       // instance if necessary.       addListener(this);     }     return this.singletonInstance;   }   //使用createAopProxy放回的AopProxy来得到代理对象。   protected Object getProxy(AopProxy aopProxy) {     return aopProxy.getProxy(this.beanClassLoader);   }

ProxyFacToryBean的父类是AdvisedSupport,Spring使用AopProxy接口把AOP代理的实 现与框架的其他部分分离开来;在AdvisedSupport中通过这样的方式来得到AopProxy,当 然这里需要得到AopProxyFacTory的帮助 – 下面我们看到Spring为我们提供的实现,来帮 助我们方便的从JDK或者cglib中得到我们想要的代理对象:

Java代码

protected synchronized AopProxy createAopProxy() {     if (!this.isActive) {       activate();     }     return getAopProxyFacTory().createAopProxy(this);   }

而在ProxyConfig中对使用的AopProxyFacTory做了定义:

Java代码

//这个DefaultAopProxyFacTory是Spring用来生成AopProxy的地方,   //当然了它包含JDK和Cglib两种实现方式。   private transient AopProxyFacTory aopProxyFacTory = new DefaultAopProxyFacTory();

其中在DefaultAopProxyFacTory中是这样生成AopProxy的:

Java代码

public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {     //首先考虑使用cglib来实现代理对象,当然如果同时目标对象不是接口的实 现类的话     if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||       advisedSupport.getProxiedInterfaces().length == 0) {       //这里判断如果不存在cglib库,直接抛出异常。       if (!cglibAvailable) {         throw new AopConfigException(             "Cannot proxy target class because CGLIB2 is not available. " +             "Add CGLIB to the class path or specify proxy interfaces.");       }       // 这里使用Cglib来生成Proxy,如果target不是接口的实现的话,返回 cglib类型的AopProxy       return CglibProxyFacTory.createCglibProxy(advisedSupport);     }     else {       // 这里使用JDK来生成Proxy,返回JDK类型的AopProxy       return new JdkDynamicAopProxy(advisedSupport);     }   }

于是我们就可以看到其中的代理对象可以由JDK或者Cglib来生成,我们看到 JdkDynamicAopProxy类和Cglib2AopProxy都实现的是AopProxy的接口,在 JdkDynamicAopProxy实现中我们可以看到Proxy是怎样生成的:

Java代码

public Object getProxy(ClassLoader classLoader) {     if (logger.isDebugEnabled()) {       Class targetClass = this.advised.getTargetSource ().getTargetClass();       logger.debug("Creating JDK dynamic proxy" +           (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));     }     Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);     //这里我们调用JDK Proxy来生成需要的Proxy实例     return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);   }

这样用Proxy包装target之后,通过ProxyFacToryBean得到对其方法的调用就被Proxy 拦截了, ProxyFacToryBean的getObject()方法得到的实际上是一个Proxy了,我们的 target对象已经被封装了。对 ProxyFacToryBean这个工厂bean而言,其生产出来的对象 是封装了目标对象的代理对象。

头脑心灵再加上双脚的才是推销员。

Spring源代码解析(五):SpringAOP获取Proxy

相关文章:

你感兴趣的文章:

标签云: