在上篇文章 Spring AOP 註解方式源碼解析 中已經獲取到了 bean 的對應加強器,以後,就能夠建立對應的代理了,Spring AOP 底層使用的是 JDK 動態代理和 CGLIB 的代理,在什麼狀況下使用JDK動態代理,何時使用 CGLIB 代理呢,下面經過源碼來看一下this
// AbstractAutoProxyCreator.java protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { //...... // 獲取的加強器 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 建立代理 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } //............ return bean; }
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, Object[] specificInterceptors, TargetSource targetSource) { // .... ProxyFactory proxyFactory = new ProxyFactory(); //複製當前類的一些屬性 proxyFactory.copyFrom(this); // 若是在配置文件中配置的aop標籤的屬性proxy-target-class爲false, if (!proxyFactory.isProxyTargetClass()) { // 是否須要代理當前類而不是代理接口,根據preserveTargetClass屬性來判斷Boolean.TRUE.equals(bd.getAttribute("preserveTargetClass") if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { // 若是代理的是接口,則添加代理接口 evaluateProxyInterfaces(beanClass, proxyFactory); } } // 對加強器進行包裝,有些加強是經過攔截器等方式來實現的,因此這裏統一封裝爲 Advisor 進行處理 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // 加入加強器 proxyFactory.addAdvisors(advisors); // 設置要代理的類 proxyFactory.setTargetSource(targetSource); // 用戶自定義代理 customizeProxyFactory(proxyFactory); // 該屬性用來控制代理工廠被配置之後,是否還容許修改通知,默認爲false proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // 建立代理 return proxyFactory.getProxy(getProxyClassLoader()); } // 添加接口代理 protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) { Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader()); boolean hasReasonableProxyInterface = false; //.... if (hasReasonableProxyInterface) { for (Class<?> ifc : targetInterfaces) { proxyFactory.addInterface(ifc); } } else { proxyFactory.setProxyTargetClass(true); } }
封裝加強,在Spring中,有些加強是經過攔截器來實現的,因此這裏統一封裝爲 Advisor 進行處理,對應方法 buildAdvisors():lua
protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) { //解析全部的 InterceptorName Advisor[] commonInterceptors = resolveInterceptorNames(); List<Object> allInterceptors = new ArrayList<>(); if (specificInterceptors != null) { // 添加參數傳進來的,即咱們自定義的加強 allInterceptors.addAll(Arrays.asList(specificInterceptors)); if (commonInterceptors.length > 0) { // 添加攔截器 if (this.applyCommonInterceptorsFirst) { allInterceptors.addAll(0, Arrays.asList(commonInterceptors)); } else { allInterceptors.addAll(Arrays.asList(commonInterceptors)); } } } //把攔截器包裝爲Advisor Advisor[] advisors = new Advisor[allInterceptors.size()]; for (int i = 0; i < allInterceptors.size(); i++) { // wrap包裝 advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i)); } return advisors; } //wrap包裝 // 僅僅對 Advisor 和 Advice進行包裝 public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { // 若是原本就是 Advisor,則直接返回 if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } // 類型不正確,異常 if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { // MethodInterceptor 類型使用 DefaultPointcutAdvisor 封裝 return new DefaultPointcutAdvisor(advice); } // 若是存在 Advisor 的適配器,也須要包裝 for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); }
建立代理getProxyspa
return proxyFactory.getProxy(getProxyClassLoader()); public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }
在這裏會判斷代理建立的方式,是使用 JDK 的動態代理仍是 CGLIB 的代理。.net
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { //這裏初步判斷代理的建立方式,若是不知足則直接使用 JDK 動態代理,若是知足條件,則進一步在判斷是否使用 JKD 動態代理仍是 CGLIB 代理 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("......"); } // 若是代理的是接口或者設置代理的類就是當前類,則使用 JDK 動態代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 不然使用 CGLIB 代理 return new ObjenesisCglibAopProxy(config); } // 條件不知足CGBLIB的方式直接使用JDK動態代理 else { return new JdkDynamicAopProxy(config); } }
這裏的 if 條件有三個:代理
1. config.isOptimize() : 用來控制經過 CGLIB 建立的代理是否使用激進的優化策略,目前僅用於 CGLIB 代理
2. config.isProxyTargetClass() : 在 Spring AOP 功能使用詳解 中瞭解到,咱們能夠強制 Spring 徹底使用 CGLIB 進行代理,只要在配置文件配置 proxy-target-class 屬性爲true便可,如:<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>,若是配置個該屬性,則會使用 CGLIB 來建立代理
3. hasNoUserSuppliedProxyInterfaces(config) : 是否存在代理接口,若是不存在代理接口,則使用 CGLIB 進行代理
若是這三個條件有一個知足,則會再進一次判斷,須要代理的類是不是接口或者是否設置的就是代理當前類,若是是,則仍是會使用 JDK 動態代理,不然的話纔會使用 CGLIB 代理。
若是代理類實現了接口,則Spring默認使用 JDK 動態代理,但能夠設置強制使用 CGLIB 代理
JDK 動態代理只能代理接口而不能代理類
CGLIB 代理類,經過繼承的方式,爲目標類生成子類,並重寫方法來實現代理,它不能代理final的類或方法
關於 JDK 動態代理和 CGLIB 代理的使用方式能夠參考 Spring AOP 功能使用詳解
接下來看下 JDK 動態代理和 CGLIB 代理的建立過程:
return new JdkDynamicAopProxy(config); // JdkDynamicAopProxy.java public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { this.advised = config; }
經過 JDK 動態代理來獲取代理的方法 getProxy():
public Object getProxy(@Nullable ClassLoader classLoader) { // 獲取代理類的接口 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); // 處理 equals , hashcode 方法 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 建立代理 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
能夠看到,Spring 使用 JDK 建立代理和咱們使用的 JDK 來建立代理是沒有區別的,都是使用 Proxy.newProxyInstance 的方式來建立;咱們知道 JDK 動態代理有個 invoke 方法,用來執行目標方法,而 JdkDynamicAopProxy 實現了 InvocationHandler 接口,全部它也會重寫該方法,在該方法中植入加強:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; // 目標類 TargetSource targetSource = this.advised.targetSource; Object target = null; try { // 若是接口沒有定義 equals 方法且當前方法是 equals 方法,則不會加強,直接返回 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // 若是接口沒有定義 hashCode方法且當前方法是 hashCode方法,則不會加強,直接返回 return hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) { return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // 若是方法所在的類和Advised是同一個類或者是父類子類關係,則直接執行 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } // 返回值 Object retVal; // 這裏對應的是expose-proxy屬性的應用,把代理暴露處理 // 目標方法內部的自我調用將沒法實施切面中的加強,因此在這裏須要把代理暴露出去 if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 獲取該方法的攔截器 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); //若是方法的攔截器爲空,則直接執行目標方法,避免建立 MethodInvocation 對象 if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 執行目標方法:method.invoke(target, args) retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // 把全部的攔截器封裝在ReflectiveMethodInvocation中,以便於鏈式調用 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 執行攔截器鏈 retVal = invocation.proceed(); } // .......... return retVal; } finally { // . } }
在執行攔截器方法 proceed 中執行加強方法,好比前置加強在方法以前執行,後置加強在方法以後執行,proceed 方法以下:
public Object proceed() throws Throwable { //當執行完全部加強方法後執行目標方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { // method.invoke(target, args) return invokeJoinpoint(); } // 獲取下一個要執行的攔截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 動態匹配 InterceptorAndDynamicMethodMatcher dm = interceptorOrInterceptionAdvice; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); // 若是可以匹配,則執行攔截器的方法, if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { // 好比 @After @Before 對應的加強器(攔截器)的方法 // 好比 @After 對應的加強器 AspectJAfterAdvice 的invoke方法爲:MethodInvocation.proceed(); return dm.interceptor.invoke(this); } else { // 若是動態匹配失敗,則跳過該攔截器,執行下一個攔截器 return proceed(); } } else { // 普通攔截器,直接調用 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
在該方法中完成了加強的植入,主要邏輯就是,每一個方法都會有一個攔截器鏈,在 AOP 中咱們稱之爲加強,而後循環執行每一個攔截器鏈,當執行完全部的攔截器後,纔會執行目標方法。好比 @After 對應的加強器AspectJAfterAdvice, @Around 對應的加強器AspectJAroundAdvice等。
以上就是 Spring 經過 JDK 動態代理來實現 AOP 的一個過程。
ObjenesisCglibAopProxy 繼承於 CglibAopProxy
return new ObjenesisCglibAopProxy(config) public CglibAopProxy(AdvisedSupport config) throws AopConfigException { this.advised = config; this.advisedDispatcher = new AdvisedDispatcher(this.advised); }
CglibAopProxy 的 getProxy 方法以下:
public Object getProxy(@Nullable ClassLoader classLoader) { // 代理的目標類 Class<?> rootClass = this.advised.getTargetClass(); Class<?> proxySuperClass = rootClass; if (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class<?>[] additionalInterfaces = rootClass.getInterfaces(); for (Class<?> additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } // 建立並配置 CGLIB Enhancer Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader &&((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); // 設置攔截器 Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); //生成代理類和建立代理 return createProxyClassAndInstance(enhancer, callbacks); } // 生成代理類和建立代理 protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { enhancer.setInterceptDuringConstruction(false); enhancer.setCallbacks(callbacks); return (this.constructorArgs != null && this.constructorArgTypes != null ? enhancer.create(this.constructorArgTypes, this.constructorArgs) : enhancer.create()); }
從上述的方法可知,Sping 使用 CGLIB 來建立代理類和代理對象和咱們使用的同樣,都是使用 Enhancer.create() 來建立,這裏主要的是設置攔截器,經過 getCallbacks () 方法來實現的,以下:
private Callback[] getCallbacks(Class<?> rootClass) throws Exception { //expose-proxy 屬性 boolean exposeProxy = this.advised.isExposeProxy(); boolean isFrozen = this.advised.isFrozen(); boolean isStatic = this.advised.getTargetSource().isStatic(); // 將攔截器封裝在 DynamicAdvisedInterceptor 中 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())); } // 將攔截器 aopInterceptor 進入到 Callback 中 Callback[] mainCallbacks = new Callback[] { aopInterceptor, // for normal advice targetInterceptor, // invoke target without considering advice, if optimized new SerializableNoOp(), // no override for methods mapped to this targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised), new HashCodeInterceptor(this.advised) }; // .............. return callbacks; }
咱們知道使用 CGLIB 來實現代理功能的時候,當代理執行的時候,會調用 intercept 方法,和 JKD 動態代理的 invoke 方法相似;Spring 中 CGLIB 的 intercept 方法以下,該方法在 DynamicAdvisedInterceptor 中,從上面的代理知道,使用它來封裝攔截器,它是 CglibAopProxy 的一個子類:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy){ Object oldProxy = null; boolean setProxyContext = false; Object target = null; // 目標類 TargetSource targetSource = this.advised.getTargetSource(); // 處理 expose-proxy 屬性,暴露代理 if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 獲取攔截器鏈 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 返回值 Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 若是攔截器爲空則直接執行目標方法 retVal = methodProxy.invoke(target, argsToUse); } else { //封裝攔截器鏈並執行 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } // 處理返回值類型 retVal = processReturnType(proxy, target, method, retVal); return retVal; // ..................... }
CGLIB 使用 CglibMethodInvocation 來封裝攔截器鏈,它是 CglibAopProxy 的一個內部類:
private static class CglibMethodInvocation extends ReflectiveMethodInvocation { @Nullable private final MethodProxy methodProxy; public CglibMethodInvocation(Object proxy, Object target, Method method,Object[] arguments, Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) { super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); this.methodProxy = (Modifier.isPublic(method.getModifiers()) && method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) && !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ? methodProxy : null); } // proceed 方法會調用該方法來執行 @Override protected Object invokeJoinpoint() throws Throwable { if (this.methodProxy != null) { return this.methodProxy.invoke(this.target, this.arguments); } else { return super.invokeJoinpoint(); } } }
當調用 proceed 方法時,和 JDK 的處理是同樣的,只不過當執行完全部的攔截器後,執行目標方法調用的是 CglibMethodInvocation 的 invokeJoinpoint 來執行而已;由於 CglibMethodInvocation 繼承於 ReflectiveMethodInvocation ,而 JDK 使用的就是 ReflectiveMethodInvocation 來執行的,ReflectiveMethodInvocation 的 invokeJoinpoint 方法爲 : method.invoke(target, args)
以上就是 Spring 使用 JDK 動態代理和 CGLIB 代理來實現 AOP 的原理。