Spring Aop原理之Advised接口
通过之前我们介绍的ProxyFactory
我们知道,Spring Aop是通过ProxyFactory
来创建代理对象的。ProxyFactory
在创建代理对象时会委托给DefaultAopProxyFactory.createAopProxy(AdvisedSupport config)
,DefaultAopProxyFactory
内部会分情况返回基于JDK的JdkDynamicAopProxy
或基于CGLIB的ObjenesisCglibAopProxy
,它俩都实现了Spring的AopProxy
接口。AopProxy
接口中只定义了一个方法,getProxy()
方法,Spring Aop创建的代理对象也就是该接口方法的返回结果。
我们先来看一下基于JDK代理的JdkDynamicAopProxy
的getProxy()的逻辑。
@Overridepublic Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader());}@Overridepublic 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);}
我们可以看到它最终是通过JDK的Proxy
来创建的代理,使用的InvocationHandler
实现类是它本身,而使用的接口是AopProxyUtils.completeProxiedInterfaces(this.advised)
的返回结果。而这个this.advised
对象是AdvisedSupport
类型,它是ProxyFactory
的父类(间接通过ProxyCreatorSupport
继承,ProxyFactory
的直接父类是ProxyCreatorSupport
,ProxyCreatorSupport
的父类是AdvisedSupport
),AdvisedSupport
的父类是ProxyConfig
,ProxyConfig
中包含创建代理对象时的一些配置项信息。以下是AopProxyUtils.completeProxiedInterfaces(this.advised)
的内部逻辑。
public static Class [] completeProxiedInterfaces(AdvisedSupport advised) { Class [] specifiedInterfaces = advised.getProxiedInterfaces(); if (specifiedInterfaces.length == 0) { // No user-specified interfaces: //check whether target class is an interface. Class targetClass = advised.getTargetClass(); if (targetClass != null && targetClass.isInterface()) { specifiedInterfaces = new Class [] {targetClass}; } } boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class); boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class); int nonUserIfcCount = 0; if (addSpringProxy) { nonUserIfcCount++; } if (addAdvised) { nonUserIfcCount++; } Class [] proxiedInterfaces = new Class [specifiedInterfaces.length + nonUserIfcCount]; System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length); if (addSpringProxy) { proxiedInterfaces[specifiedInterfaces.length] = SpringProxy.class; } if (addAdvised) { proxiedInterfaces[proxiedInterfaces.length - 1] = Advised.class; } return proxiedInterfaces;}
我们可以看到其会在!advised.isOpaque() && !advised.isInterfaceProxied(Advised.class)
返回true
的情况下加上本文的主角Advised
接口。isOpaque()
是ProxyConfig
中的一个方法,对应的是opaque
属性,表示是否禁止将代理对象转换为Advised
对象,默认是false
。!advised.isInterfaceProxied(Advised.class)
表示将要代理的目标对象类没有实现Advised
接口,对于我们自己应用的Class
来说,一般都不会自己去实现Advised
接口的,所以这个通常也是返回true
,所以通常创建Aop代理对象时是会创建包含Advised
接口的代理对象的,即上述的proxiedInterfaces[proxiedInterfaces.length - 1] = Advised.class
会被执行。
JdkDynamicAopProxy
创建代理对象应用的InvocationHandler
是其自身,所以我们在调用JdkDynamicAopProxy
创建的代理对象的任何方法时都将调用JdkDynamicAopProxy
实现的InvocationHandler
接口的invoke(Object proxy, Method method, Object[] args)
方法。该方法实现如下: public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class targetClass = null; Object target = null; try { if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement // the equals(Object) method itself. return equals(args[0]); } if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() // method itself. return hashCode(); } if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection( this.advised, method, args); } Object retVal; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // May be null. Get as late as possible to // minimize the time we "own" the target, // in case it comes from a pool. target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } // Get the interception chain for this method. List
其中关于Advised
接口方法调用最核心的一句是如下这句。我们可以看到,当我们调用的目标方法是定义自Advised
接口时,对应方法的调用将委托给AopUtils.invokeJoinpointUsingReflection(this.advised, method, args)
,invokeJoinpointUsingReflection
方法的逻辑比较简单,是通过Java反射来调用目标方法。在这里invokeJoinpointUsingReflection
传递的目标对象正是AdvisedSupport
类型的this.advised
对象。
if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}
AdvisedSupport
类是实现了Advised
接口的,所以Spring Aop创建了基于Advised
接口的代理对象后在调用Advised
接口方法时可以把它委托给AdvisedSupport
。而我们知道Spring Aop代理对象的创建正是基于AdvisedSupport
的配置进行的(配置项主要都定义在AdvisedSupport
的父类ProxyConfig
类中)。创建代理对象时应用AdvisedSupport
,调用Advised
接口方法也用同一个实现了Advised
接口的AdvisedSupport
对象,所以这个过程在Spring Aop内部就可以很好的衔接。接着我们来看一下Advised
接口的定义。
public interface Advised extends TargetClassAware { boolean isFrozen(); boolean isProxyTargetClass(); Class [] getProxiedInterfaces(); boolean isInterfaceProxied(Class intf); void setTargetSource(TargetSource targetSource); TargetSource getTargetSource(); void setExposeProxy(boolean exposeProxy); boolean isExposeProxy(); void setPreFiltered(boolean preFiltered); boolean isPreFiltered(); Advisor[] getAdvisors(); void addAdvisor(Advisor advisor) throws AopConfigException; void addAdvisor(int pos, Advisor advisor) throws AopConfigException; boolean removeAdvisor(Advisor advisor); void removeAdvisor(int index) throws AopConfigException; int indexOf(Advisor advisor); boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException; void addAdvice(Advice advice) throws AopConfigException; void addAdvice(int pos, Advice advice) throws AopConfigException; boolean removeAdvice(Advice advice); int indexOf(Advice advice); String toProxyConfigString();}
Advised
接口中定义的方法还是非常多的,通过它我们可以在运行时了解我们的代理对象是基于CGLIB的还是基于JDK代理的;可以了解我们的代理对应应用了哪些Advisor
;也可以在运行时给我们的代理对象添加和删除Advisor/Advise
。本文旨在描述Spring Aop在创建代理对象时是如何基于Advised
接口创建代理的,以及我们能够应用Advised
接口做哪些事。文中应用的是Spring创建基于JDK代理对象的过程为示例讲解的,其实基于CGLIB的代理也是一样的。关于CGLIB的代理过程、本文中描述的一些核心类以及本文的核心——Advised
接口的接口方法说明等请有兴趣的朋友参考Spring的API文档和相关的源代码。