Spring源碼學習之動態代理實現流程
註:這裡不闡述Spring和AOP的一些基本概念和用法,直接進入正題。
流程
Spring所管理的對象大體會經過確定實例化對象類型、推斷構造方法創建對象(實例化)、設置屬性、初始化等等步驟。在對象初始化階段,Spring為開發者提供瞭一個BeanPostProcessor接口,它會在對象初始化之前和初始化之後被調用(初始化,不是實例化,對應實例化的是InstantiationAwareBeanPostProcessor接口)。
public interface BeanPostProcessor { //初始化之前 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; //初始化之後 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
在對象初始化之後會調用postProcessAfterInitialization方法,該方法返回一個Object。如果成功返回瞭一個對象,那麼容器中相應beanName對應的實例就將會是這個對象。
本文主要分析動態代理,我們著重看AnnotationAwareAspectJAutoProxyCreator。先來看一下它的繼承關系:
AnnotationAwareAspectJAutoProxyCreator最終實現瞭BeanPostProcessor接口(也實現瞭InstantiationAwareBeanPostProcessor接口),可以看到繼承關系比較復雜。當前我們關註的postProcessAfterInitialization方法實現在它的父類AbstractAutoProxyCreator中(隻保留瞭部分代碼):
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
這裡主要看看wrapIfNecessary方法(隻保留瞭部分代碼):
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); ...... 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; } ...... }
其中核心的是兩個方法調用,分別是getAdvicesAndAdvisorsForBean和createProxy。getAdvicesAndAdvisorsForBean會返回一個對象數組,包含aop相關的一些對象,如果是一個普通的不需要代理的對象會返回一個空Object數組,也就是DO_NOT_PROXY;createProxy方法則是創建代理類。
先看看getAdvicesAndAdvisorsForBean方法:
protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException;
getAdvicesAndAdvisorsForBean方法在當前類(AbstractAutoProxyCreator)中是一個抽象方法,由子類AbstractAdvisorAutoProxyCreator實現:
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator { @Override protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } }
代碼很清晰,我們進入findEligibleAdvisors方法,看方法名也知道它會完成尋找Advisor的工作:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //尋找Advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); //針對指定的bean,過濾可用的Advisor,比如根據註解匹配 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
首先進入findCandidateAdvisors方法:
protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); return advisors; }
我們這裡主要看看aspectj的邏輯,所以看看aspectJAdvisorsBuilder.buildAspectJAdvisors方法(隻保留瞭主要代碼):
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = null; ...... synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { //獲取所有管理的beanName String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false); //遍歷每個beanName for (String beanName : beanNames) { //從beanFactory獲取Class Class<?> beanType = this.beanFactory.getType(beanName); //檢查對應的Class是否實現Aspect註解 if (this.advisorFactory.isAspect(beanType)) { //說明這個beanName對應的類是一個切面 aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); //獲取Advisor,主要是解析對象中關於AOP的註解,比如Pointcut List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); if (this.beanFactory.isSingleton(beanName)) { //就放入緩存,後面就不用重新解析瞭 this.advisorsCache.put(beanName, classAdvisors); } advisors.addAll(classAdvisors); } } } this.aspectBeanNames = aspectNames; return advisors; } } ...... }
會從beanFactory中尋找所有管理的beanName,返回一個String數組,然後遍歷數組,從beanFactory中根據beanName獲取對應的Class,然後再看對應的Class是否有Aspect註解,如果有對應的註解,那麼就表示這個對象是一個切面。接下來就需要進行解析,生成真正的Advisor對象,最後放入緩存。
可以看看isAspect方法是如何判斷的:
@Override public boolean isAspect(Class<?> clazz) { return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz)); } private boolean hasAspectAnnotation(Class<?> clazz) { return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null); }
邏輯很清晰,主要就是看有沒有Aspect註解。 但是這裡要註意,這個buildAspectJAdvisors方法通常不是在這裡調用的(”這裡“的意思是postProcessAfterInitialization的流程)。回到AnnotationAwareAspectJAutoProxyCreator繼承關系圖中,它也實現瞭InstantiationAwareBeanPostProcessor接口,同樣在其父類AbstractAutoProxyCreator中實現瞭postProcessBeforeInstantiation方法,這個方法會在對象實例化(不是初始化)之前調用,在該方法的邏輯裡通常會首先觸發buildAspectJAdvisors方法的執行,執行之後會把結果緩存起來。
好瞭,再回到findEligibleAdvisors方法,上面代碼已經貼瞭,這裡就不貼瞭。獲取到Advisor列表之後,要從中找到能用於指定類的Advisor列表,然後返回。接下來就要為指定的對象創建代理對象瞭,也就是AbstractAutoProxyCreator類的createProxy方法:
protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); for (Advisor advisor : advisors) { proxyFactory.addAdvisor(advisor); } proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); }
代理對象是由ProxyFactory代理工廠創建的,我們先看看這個工廠是如何創建代理對象的,也就是proxyFactory.getProxy方法:
public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }
createAopProxy方法會返回一個AopProxy,該方法定義在ProxyFactory的父類ProxyCreatorSupport中:
public class ProxyCreatorSupport extends AdvisedSupport { private AopProxyFactory aopProxyFactory; public ProxyCreatorSupport() { //設置默認的代理工廠DefaultAopProxyFactory this.aopProxyFactory = new DefaultAopProxyFactory(); } public AopProxyFactory getAopProxyFactory() { //獲取代理工廠,默認就是DefaultAopProxyFactory return this.aopProxyFactory; } protected final synchronized AopProxy createAopProxy() { //先獲取代理工廠,然後調用工廠的createAopProxy方法創建AopProxy return getAopProxyFactory().createAopProxy(this); } }
上面貼出瞭關鍵代碼,getAopProxyFactory默認返回的是一個DefaultAopProxyFactory工廠類,來看看DefaultAopProxyFactory的createAopProxy方法:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
代碼中有一些代理配置的判斷,這裡不用關心。可以看到它提供瞭兩個AopProxy,分別是基於JDK的JdkDynamicAopProxy和基於cglib的ObjenesisCglibAopProxy。由於JDK提供的動態代理實現最終生成的代理類默認會繼承Proxy類,實現被代理類實現的接口,因為Java是單繼承,所以隻能通過接口實現,也就限制瞭要使用JDK提供的動態代理,必須要基於接口。而使用cglib基於字節碼的改造則沒有這個限制,所以Spring提供瞭這兩種方式,根據被代理類的實際情況來選擇。
關於每個AopProxy是如何創建代理類的,這裡就先不跟瞭~
總結
總的來說,動態代理是實現AOP的重要手段,Spring提供的動態代理主要依靠其提供的BeanPostProcessor,也稱之為後置處理器。除瞭BeanPostProcessor之外,還有InstantiationAwareBeanPostProcessor(也繼承瞭BeanPostProcessor),它們會在bean的生命周期的特定階段被調用,以開放給開發者處理和調整對象的入口或者手段。動態代理依托後置處理器,在後置處理器的邏輯中使用AopProxy創建瞭被代理對象的代理類,然後代替原有類存入Spring的bean工廠中,之後根據beanName獲取的實例對象就不再是原對象實例,而是代理類。而AopProxy是由AopProxyFactory接口生成,目前該接口隻有DefaultAopProxyFactory實現類,其提供瞭兩種AopProxy,分別基於原生JDK提供的動態代理和cgib,根據實際情況選擇。
到此這篇關於Spring源碼學習之動態代理實現流程的文章就介紹到這瞭,更多相關Spring動態代理實現內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Spring AOP底層源碼詳解
- 手把手帶你實現一個萌芽版的Spring容器
- 深度解析SpringBoot中@Async引起的循環依賴
- Spring菜鳥教你看源碼沖面試
- spring boot項目使用@Async註解的坑