Spring Aop 代理創建方式:https://www.cnblogs.com/jhxxb/p/14097866.html
最后都會走到 ProxyCreatorSupport#createAopProxy 中,拿到 AopProxy,然后調用 getProxy 方法獲取代理對象
public class ProxyCreatorSupport extends AdvisedSupport { protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); }
DefaultAopProxyFactory
createAopProxy 方法,它的唯一實現為 DefaultAopProxyFactory
/** * 默認情況下,實現了接口,就使用 JDK 動態代理,沒有就使用 CGLIB */ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } /** * Determine whether the supplied {@link AdvisedSupport} has only the {@link org.springframework.aop.SpringProxy} interface specified (or no proxy interfaces specified at all). */ private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }
AopProxy 有兩個實現類,通過 getProxy 方法創建代理對象
JdkDynamicAopProxy
/** * 實現了 InvocationHandler,所以處理器就是自己。會實現 invoke 方法 * 是 final 類,默認是 package 的訪問權限 */ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { /** * 保存這個 AOP 代理所有的配置信息,包括所有的增強器等等 */ private final AdvisedSupport advised; // 標記 equals 和 hashCode 方法是否定義在了接口上 private boolean equalsDefined; private boolean hashCodeDefined; public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); // 內部再校驗一次:必須有至少一個增強器和目標實例才行 if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { throw new AopConfigException("No advisors and no TargetSource specified"); } this.advised = config; } @Override public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } /** * 真正創建 JDK 動態代理實例的地方 */ @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } // 這部很重要,就是去找接口,我們看到最終代理的接口就是這里返回的所有接口們(除了我們自己的接口,還有 Spring 默認的一些接口)大致過程如下: // 1、獲取目標對象自己實現的接口們(最終肯定都會被代理的) // 2、是否添加 SpringProxy 接口:目標對象實現對就不添加了,沒實現過就添加 true // 3、是否新增 Adviced 接口,注意不是 Advice 通知接口。實現過就不實現了,沒實現過並且 advised.isOpaque()=false 就添加(默認是會添加的) // 4、是否新增 DecoratingProxy 接口(Spring4.3 后才提供)。傳入的參數 decoratingProxy 為 true,並且沒實現過就添加(顯然這里,首次進來是會添加的) // 5、代理類的接口一共是目標對象的接口加上面三個接口 SpringProxy、Advised、DecoratingProxy(SpringProxy 是個標記接口而已,其余的接口都有對應的方法的) Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 第三個參數傳的 this,處理器就是自己,到此一個代理對象就此 new 出來了 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } /** * 看接口里有沒有自己定義 equals 和 hashCode方法,這個很重要,然后標記一下 */ private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) { for (Class<?> proxiedInterface : proxiedInterfaces) { Method[] methods = proxiedInterface.getDeclaredMethods(); // 此處用的是 getDeclaredMethods,只會找自己的 for (Method method : methods) { if (AopUtils.isEqualsMethod(method)) { this.equalsDefined = true; } if (AopUtils.isHashCodeMethod(method)) { this.hashCodeDefined = true; } if (this.equalsDefined && this.hashCodeDefined) { // 兩個都找到了就沒必要繼續循環 return; } } } } /** * 對於這部分代碼和采用 CGLIB 的大部分邏輯都是一樣的,Spring 對此的解釋很有意思: * 本來是可以抽取出來的,使得代碼看起來更優雅。但是因為此會帶來 10% 的性能損耗,所以 Spring 最終采用了粘貼復制的方式各用一份 * Spring 說它提供了基礎的套件,來保證兩個的執行行為是一致的。 * proxy:指的是我們所代理的那個真實對象;method:指的是我們所代理的那個真實對象的某個方法的 Method 對象;args:指的是調用那個真實對象方法的參數。 */ @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; // 進入 invoke 方法后,最終操作的是 targetSource 對象 // 因為 InvocationHandler 持久的就是 targetSource,最終通過 getTarget 拿到目標對象 TargetSource targetSource = this.advised.targetSource; Object target = null; try { // “通常情況” Spring AOP 不會對 equals、hashCode 方法進行攔截增強,所以此處做了處理 // equalsDefined 為 false(表示自己沒有定義過 eequals 方法),那就交給代理去比較 // hashCode 同理,只要你自己沒有實現過此方法,那就交給代理 // 需要注意的是:這里統一指的是,如果接口上有此方法,但是你自己並沒有實現 equals 和 hashCode 方法,那就走 AOP 這里的實現 // 如果接口上沒有定義此方法,只是實現類里自己 @Override 了 HashCode,那是無效的,就是普通執行 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return hashCode(); } // DecoratingProxy 的方法和 Advised 接口的方法,都是最終調用了 config,也就是 this.advised 去執行的 else if (method.getDeclaringClass() == DecoratingProxy.class) { return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; // 這個是最終該方法的返回值 // 是否暴露代理對象,默認 false 可配置為 true,如果暴露就意味着允許在線程內共享代理對象, // 注意這是在線程內,也就是說同一線程的任意地方都能通過 AopContext 獲取該代理對象,這應該算是比較高級一點的用法了。 if (this.advised.exposeProxy) { // 這里緩存一份代理對象在 oldProxy 里,后面有用 oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 通過目標源獲取目標對象(此處 Spring 建議獲取目標對象靠后獲取,而不是放在上面) target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 獲取作用在這個方法上的所有攔截器鏈,參見 DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice 方法 // 會根據切點表達式去匹配這個方法。因此其實每個方法都會進入這里,只是有很多方法的 chain 是 Empty 而已 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { // 若攔截器為空,那就直接調用目標方法了 // 對參數進行適配:主要處理一些數組類型的參數,看是表示一個參數,還是表示多個參數(可變參數最終到此都是數組類型,所以最好是需要一次適配) Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 直接調用目標方法 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // 創建一個 invocation ,此處為 ReflectiveMethodInvocation 最終是通過它,去執行前置加強、后置加強等等邏輯 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 此處會執行所有的攔截器鏈,交給 AOP 聯盟的 MethodInvocation 去處理。當然實現還是 Spring 的 ReflectiveMethodInvocation retVal = invocation.proceed(); } // 獲取返回值的類型 Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // 一些列的判斷條件,如果返回值不為空,且為目標對象的話,就直接將目標對象賦值給 retVal retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { // 返回 null,且還不是 Void 類型,就拋錯 throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // 釋放 targetSource.releaseTarget(target); } if (setProxyContext) { // 把老的代理對象重新 set 進去 AopContext.setCurrentProxy(oldProxy); } } } /** * AOP 幫我們實現的 equals 方法 */ @Override public boolean equals(@Nullable Object other) { if (other == this) { return true; } if (other == null) { return false; } JdkDynamicAopProxy otherProxy; if (other instanceof JdkDynamicAopProxy) { otherProxy = (JdkDynamicAopProxy) other; } else if (Proxy.isProxyClass(other.getClass())) { InvocationHandler ih = Proxy.getInvocationHandler(other); if (!(ih instanceof JdkDynamicAopProxy)) { return false; } otherProxy = (JdkDynamicAopProxy) ih; } else { return false; } return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised); } /** * AOP 幫我們實現的 hashCode 方法 */ @Override public int hashCode() { return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode(); } }
除了實現類里自己寫的方法(接口上沒有),其余方法統一都會進入代理的 invoke() 方法里面。只是 invoke 上做了很多特殊處理,比如 DecoratingProxy 和 Advised 等的方法,都是直接執行了。
object 的方法中,toString() 方法會被增強。
ObjenesisCglibAopProxy
/** * 繼承自 CglibAopProxy,它只重寫了 createProxyClassAndInstance 方法 */ class ObjenesisCglibAopProxy extends CglibAopProxy { private static final Log logger = LogFactory.getLog(ObjenesisCglibAopProxy.class); // 另外一種創建實例的方式,可以不用空的構造函數 private static final SpringObjenesis objenesis = new SpringObjenesis(); public ObjenesisCglibAopProxy(AdvisedSupport config) { super(config); } @Override protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { // 創建一個代理得實例 Class<?> proxyClass = enhancer.createClass(); Object proxyInstance = null; if (objenesis.isWorthTrying()) { // 如果為 true,就采用 objenesis 去 new 一個實例 try { proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache()); } catch (Throwable ex) { logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex); } } if (proxyInstance == null) { // 若果還為 null,就再去拿構造函數(指定參數的) try { Constructor<?> ctor = (this.constructorArgs != null ? proxyClass.getDeclaredConstructor(this.constructorArgTypes) : proxyClass.getDeclaredConstructor()); // 通過此構造函數去 new 一個實例 ReflectionUtils.makeAccessible(ctor); proxyInstance = (this.constructorArgs != null ? ctor.newInstance(this.constructorArgs) : ctor.newInstance()); } catch (Throwable ex) { throw new AopConfigException("Unable to instantiate proxy using Objenesis, and regular proxy instantiation via default constructor fails as well", ex); } } ((Factory) proxyInstance).setCallbacks(callbacks); return proxyInstance; } }
父類 CglibAopProxy
class CglibAopProxy implements AopProxy, Serializable { /** * 它的兩個 getProxy() 相對來說比較簡單,就是使用 CGLIB 的方式,利用 Enhancer 創建了一個增強的實例 * 這里面比較復雜的地方在:getCallbacks() 這步是比較繁瑣的 * setCallbackFilter 就是看看哪些方法需要攔截,哪些不需要 */ @Override public Object getProxy() { return getProxy(null); } // CGLIB 重寫的兩個方法 @Override public boolean equals(@Nullable Object other) { return (this == other || (other instanceof CglibAopProxy && AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised))); } @Override public int hashCode() { return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode(); } /** * 最后,所有的被代理的類的所有的方法調用,都會進入 DynamicAdvisedInterceptor#intercept 這個方法里面來(相當於 JDK 動態代理的 invoke 方法) * 它實現了 MethodInterceptor 接口 */ private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public DynamicAdvisedInterceptor(AdvisedSupport advised) { this.advised = advised; } @Override @Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; // 目標對象源 TargetSource targetSource = this.advised.getTargetSource(); try { if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 拿到目標對象,這里就是使用 targetSource 的意義,它提供多個實現類,從而實現了更多的可能性 // 比如:SingletonTargetSource、HotSwappableTargetSource、PrototypeTargetSource、ThreadLocalTargetSource 等 target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 一樣的,也是拿到和這個方法匹配的所有增強器和通知,和 JDK Proxy 中是一樣的 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // 沒有增強器,同時該方法是 public 的,就直接調用目標方法(不攔截) Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // CglibMethodInvocation 這里采用的是 CglibMethodInvocation,它是 ReflectiveMethodInvocation 的子類,到這里就和 JDK Proxy 保持一致了 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } } @Override public boolean equals(@Nullable Object other) { return (this == other || (other instanceof DynamicAdvisedInterceptor && this.advised.equals(((DynamicAdvisedInterceptor) other).advised))); } @Override public int hashCode() { return this.advised.hashCode(); } } private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
和 JDK 的一樣,Object 的方法,只有 toString() 會被攔截(執行通知)
生成出來的代理對象,Spring 默認都給你實現了接口:SpringProxy、Advised
和 JDK 不同的是,比如 equals 和 hashCode 等方法根本就不會進入 intecept 方法,而是在 getCallbacks() 那里就給特殊處理掉了
總結
關於 final 方法
- JDK 代理:因為接口的方法不能使用 final 關鍵字,所以編譯器就過不去
- CGLIB 代理:final 修飾某個方法后,不報錯。但也不會攔截了
關於 static 方法
- JDK 代理:static 修飾接口上的方法,要求有 body 體(JDK8 后支持)。但是因為子類不能 @Override了,所以編譯就報錯了
- CGLIB 代理:父類方法用 static 修飾后,子類也是無法進行重寫的。因此不報錯,但也不會攔截了
關於非 public 方法
- JDK 代理:接口中的方法都是 public的,所以對於它不存在這種現象
- CGLIB 代理:記住結論,只有 private 的方法不能被代理(因為子類無法訪問),其余的訪問權限級別的,都能夠被正常代理
使用 JDK 動態代理的入口方法是 JdkDynamicAopProxy.invoke() 方法,使用 CGLIB 動態代理入口方法是 DynamicAdvisedInterceptor.intercept() 方法
JDK 動態代理使用的 MethodInvocation 是: ReflectiveMethodInvocation,CGLIB 動態代理使用的是 CglibMethodInvocation,它倆都是 ProxyMethodInvocation 接口的實現類。且 CglibMethodInvocation 繼承自 ReflectiveMethodInvocation
CGLib 更適合代理不需要頻繁實例化的類,而 Spring 絕大多數 Bean 都是單例的,因此在 Spring AOP 中推薦使用 CGLib,它的功能更強大些