共享社区

首页 » 编程技巧共享 » JAVA编程技巧共享 » Spring源代码解析(五):Spring AOP获取Proxy
java - 2008-5-20 11:34:00
下面我们来看看Spring的AOP的一些相关代码是怎么得到Proxy的,让我们我们先看看AOP和Spring AOP的一些基本概念:
Advice:
    通知,制定在连接点做什么,在Sping中,他主要描述Spring围绕方法调用注入的额外的行为,Spring提供的通知类型有:
    before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,这些都是Spring AOP定义的接口类,具体的动作实现需要用户程序来完成。
Pointcut:
切点,其决定一个advice应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个advice作为目标的一组方法。Springpointcut通常意味着标示方法,可以选择一组方法调用作为pointcut,Spring提供了具体的切点来给用户使用,比如正则表达式切点JdkRegexpMethodPointcut通过正则表达式对方法名进行匹配,其通过使用AbstractJdkRegexpMethodPointcut中的对MethodMatcher接口的实现来完成pointcut功能:
  1. public final boolean matches(Method method, Class targetClass) { 
  2.    //这里通过放射得到方法的全名 
  3.    String patt = method.getDeclaringClass().getName() + "." + method.getName(); 
  4.    for (int i = 0; i < this.patterns.length; i++) { 
  5.        // 这里是判断是否和方法名是否匹配的代码 
  6.        boolean matched = matches(patt, i); 
  7.        if (matched) { 
  8.            for (int j = 0; j < this.excludedPatterns.length; j++) { 
  9.                boolean excluded = matchesExclusion(patt, j); 
  10.                if(excluded) { 
  11.                    return false; 
  12.                } 
  13.            } 
  14.            return true; 
  15.        } 
  16.    } 
  17.    return false; 
  18. } 
在JDKRegexpMethodPointcut中通过JDK中的正则表达式匹配来完成pointcut的最终确定:
  1. protected boolean matches(String pattern, int patternIndex) { 
  2.    Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern); 
  3.    return matcher.matches(); 
  4. } 
Advisor:
当我们完成额外的动作设计(advice)和额外动作插入点的设计(pointcut)以后,我们需要一个对象把他们结合起来,这就是通知器 - advisor,定义应该在哪里应用哪个通知。Advisor的实现有:DefaultPointcutAdvisor他有两个属性advice和 pointcut来让我们配置advice和pointcut。
接着我们就可以通过ProxyFactoryBean来配置我们的代理对象和方面行为,在ProxyFactoryBean中有 interceptorNames来配置已经定义好的通知器-advisor,虽然这里的名字叫做interceptNames,但实际上是供我们配置 advisor的地方,具体的代理实现通过JDK 的Proxy或者CGLIB来完成。因为ProxyFactoryBean是一个FactoryBean,在ProxyFactoryBean中我们通过 getObject()可以直接得到代理对象:
  1. public Object getObject() throws BeansException { 
  2.    //这里初始化通知器链 
  3.    initializeAdvisorChain(); 
  4.    if (isSingleton()) { 
  5.    //根据定义需要生成单件的Proxy 
  6.        return getSingletonInstance(); 
  7.    } 
  8.    else { 
  9.    ....... 
  10.        //这里根据定义需要生成Prototype类型的Proxy 
  11.        return newPrototypeInstance(); 
  12.    } 
  13. } 
我们看看怎样生成单件的代理对象:
  1. private synchronized Object getSingletonInstance() { 
  2.    if (this.singletonInstance == null) { 
  3.        this.targetSource = freshTargetSource(); 
  4.        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { 
  5.            // 这里设置代理对象的接口 
  6.            setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass())); 
  7.        } 
  8.        // Eagerly initialize the shared singleton instance. 
  9.        super.setFrozen(this.freezeProxy); 
  10.        // 注意这里的方法会使用ProxyFactory来生成我们需要的Proxy 
  11.        this.singletonInstance = getProxy(createAopProxy()); 
  12.        // We must listen to superclass advice change events to recache the singleton 
  13.        // instance if necessary. 
  14.        addListener(this); 
  15.    } 
  16.    return this.singletonInstance; 
  17. } 
  18. 
  19. //使用createAopProxy放回的AopProxy来得到代理对象。 
  20. protected Object getProxy(AopProxy aopProxy) { 
  21.    return aopProxy.getProxy(this.beanClassLoader); 
  22. } 
ProxyFactoryBean的父类是AdvisedSupport,Spring使用AopProxy接口把AOP代理的实现与框架的其他部分分离开来;在AdvisedSupport中通过这样的方式来得到AopProxy,当然这里需要得到AopProxyFactory的帮助 - 下面我们看到Spring为我们提供的实现,来帮助我们方便的从JDK或者cglib中得到我们想要的代理对象:
# protected synchronized AopProxy createAopProxy() { 
#    if (!this.isActive) { 
#        activate(); 
#    } 
#    return getAopProxyFactory().createAopProxy(this); 
# }
而在ProxyConfig中对使用的AopProxyFactory做了定义:
  1. //这个DefaultAopProxyFactory是Spring用来生成AopProxy的地方, 
  2. //当然了它包含JDK和Cglib两种实现方式。 
  3. private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory(); 
其中在DefaultAopProxyFactory中是这样生成AopProxy的:
# 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是怎样生成的:

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

这样用Proxy包装target之后,通过ProxyFactoryBean得到对其方法的调用就被Proxy拦截了, ProxyFactoryBean的getObject()方法得到的实际上是一个Proxy了,我们的target对象已经被封装了。对 ProxyFactoryBean这个工厂bean而言,其生产出来的对象是封装了目标对象的代理对象。
1
查看完整版本: Spring源代码解析(五):Spring AOP获取Proxy