Spring源碼學(xué)習(xí)之動(dòng)態(tài)代理實(shí)現(xiàn)流程
注:這里不闡述Spring和AOP的一些基本概念和用法,直接進(jìn)入正題。
流程
Spring所管理的對(duì)象大體會(huì)經(jīng)過確定實(shí)例化對(duì)象類型、推斷構(gòu)造方法創(chuàng)建對(duì)象(實(shí)例化)、設(shè)置屬性、初始化等等步驟。在對(duì)象初始化階段,Spring為開發(fā)者提供了一個(gè)BeanPostProcessor接口,它會(huì)在對(duì)象初始化之前和初始化之后被調(diào)用(初始化,不是實(shí)例化,對(duì)應(yīng)實(shí)例化的是InstantiationAwareBeanPostProcessor接口)。
public interface BeanPostProcessor { //初始化之前 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; //初始化之后 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
在對(duì)象初始化之后會(huì)調(diào)用postProcessAfterInitialization方法,該方法返回一個(gè)Object。如果成功返回了一個(gè)對(duì)象,那么容器中相應(yīng)beanName對(duì)應(yīng)的實(shí)例就將會(huì)是這個(gè)對(duì)象。
本文主要分析動(dòng)態(tài)代理,我們著重看AnnotationAwareAspectJAutoProxyCreator。先來看一下它的繼承關(guān)系:
AnnotationAwareAspectJAutoProxyCreator最終實(shí)現(xiàn)了BeanPostProcessor接口(也實(shí)現(xiàn)了InstantiationAwareBeanPostProcessor接口),可以看到繼承關(guān)系比較復(fù)雜。當(dāng)前我們關(guān)注的postProcessAfterInitialization方法實(shí)現(xiàn)在它的父類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; } ...... }
其中核心的是兩個(gè)方法調(diào)用,分別是getAdvicesAndAdvisorsForBean和createProxy。getAdvicesAndAdvisorsForBean會(huì)返回一個(gè)對(duì)象數(shù)組,包含aop相關(guān)的一些對(duì)象,如果是一個(gè)普通的不需要代理的對(duì)象會(huì)返回一個(gè)空Object數(shù)組,也就是DO_NOT_PROXY;createProxy方法則是創(chuàng)建代理類。
先看看getAdvicesAndAdvisorsForBean方法:
protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException;
getAdvicesAndAdvisorsForBean方法在當(dāng)前類(AbstractAutoProxyCreator)中是一個(gè)抽象方法,由子類AbstractAdvisorAutoProxyCreator實(shí)現(xiàn):
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(); } }
代碼很清晰,我們進(jìn)入findEligibleAdvisors方法,看方法名也知道它會(huì)完成尋找Advisor的工作:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //尋找Advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); //針對(duì)指定的bean,過濾可用的Advisor,比如根據(jù)注解匹配 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
首先進(jìn)入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); //遍歷每個(gè)beanName for (String beanName : beanNames) { //從beanFactory獲取Class Class<?> beanType = this.beanFactory.getType(beanName); //檢查對(duì)應(yīng)的Class是否實(shí)現(xiàn)Aspect注解 if (this.advisorFactory.isAspect(beanType)) { //說明這個(gè)beanName對(duì)應(yīng)的類是一個(gè)切面 aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); //獲取Advisor,主要是解析對(duì)象中關(guān)于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; } } ...... }
會(huì)從beanFactory中尋找所有管理的beanName,返回一個(gè)String數(shù)組,然后遍歷數(shù)組,從beanFactory中根據(jù)beanName獲取對(duì)應(yīng)的Class,然后再看對(duì)應(yīng)的Class是否有Aspect注解,如果有對(duì)應(yīng)的注解,那么就表示這個(gè)對(duì)象是一個(gè)切面。接下來就需要進(jìn)行解析,生成真正的Advisor對(duì)象,最后放入緩存。
可以看看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注解。 但是這里要注意,這個(gè)buildAspectJAdvisors方法通常不是在這里調(diào)用的(”這里“的意思是postProcessAfterInitialization的流程)。回到AnnotationAwareAspectJAutoProxyCreator繼承關(guān)系圖中,它也實(shí)現(xiàn)了InstantiationAwareBeanPostProcessor接口,同樣在其父類AbstractAutoProxyCreator中實(shí)現(xiàn)了postProcessBeforeInstantiation方法,這個(gè)方法會(huì)在對(duì)象實(shí)例化(不是初始化)之前調(diào)用,在該方法的邏輯里通常會(huì)首先觸發(fā)buildAspectJAdvisors方法的執(zhí)行,執(zhí)行之后會(huì)把結(jié)果緩存起來。
好了,再回到findEligibleAdvisors方法,上面代碼已經(jīng)貼了,這里就不貼了。獲取到Advisor列表之后,要從中找到能用于指定類的Advisor列表,然后返回。接下來就要為指定的對(duì)象創(chuàng)建代理對(duì)象了,也就是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()); }
代理對(duì)象是由ProxyFactory代理工廠創(chuàng)建的,我們先看看這個(gè)工廠是如何創(chuàng)建代理對(duì)象的,也就是proxyFactory.getProxy方法:
public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }
createAopProxy方法會(huì)返回一個(gè)AopProxy,該方法定義在ProxyFactory的父類ProxyCreatorSupport中:
public class ProxyCreatorSupport extends AdvisedSupport { private AopProxyFactory aopProxyFactory; public ProxyCreatorSupport() { //設(shè)置默認(rèn)的代理工廠DefaultAopProxyFactory this.aopProxyFactory = new DefaultAopProxyFactory(); } public AopProxyFactory getAopProxyFactory() { //獲取代理工廠,默認(rèn)就是DefaultAopProxyFactory return this.aopProxyFactory; } protected final synchronized AopProxy createAopProxy() { //先獲取代理工廠,然后調(diào)用工廠的createAopProxy方法創(chuàng)建AopProxy return getAopProxyFactory().createAopProxy(this); } }
上面貼出了關(guān)鍵代碼,getAopProxyFactory默認(rèn)返回的是一個(gè)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); } }
代碼中有一些代理配置的判斷,這里不用關(guān)心。可以看到它提供了兩個(gè)AopProxy,分別是基于JDK的JdkDynamicAopProxy和基于cglib的ObjenesisCglibAopProxy。由于JDK提供的動(dòng)態(tài)代理實(shí)現(xiàn)最終生成的代理類默認(rèn)會(huì)繼承Proxy類,實(shí)現(xiàn)被代理類實(shí)現(xiàn)的接口,因?yàn)镴ava是單繼承,所以只能通過接口實(shí)現(xiàn),也就限制了要使用JDK提供的動(dòng)態(tài)代理,必須要基于接口。而使用cglib基于字節(jié)碼的改造則沒有這個(gè)限制,所以Spring提供了這兩種方式,根據(jù)被代理類的實(shí)際情況來選擇。
關(guān)于每個(gè)AopProxy是如何創(chuàng)建代理類的,這里就先不跟了~
總結(jié)
總的來說,動(dòng)態(tài)代理是實(shí)現(xiàn)AOP的重要手段,Spring提供的動(dòng)態(tài)代理主要依靠其提供的BeanPostProcessor,也稱之為后置處理器。除了BeanPostProcessor之外,還有InstantiationAwareBeanPostProcessor(也繼承了BeanPostProcessor),它們會(huì)在bean的生命周期的特定階段被調(diào)用,以開放給開發(fā)者處理和調(diào)整對(duì)象的入口或者手段。動(dòng)態(tài)代理依托后置處理器,在后置處理器的邏輯中使用AopProxy創(chuàng)建了被代理對(duì)象的代理類,然后代替原有類存入Spring的bean工廠中,之后根據(jù)beanName獲取的實(shí)例對(duì)象就不再是原對(duì)象實(shí)例,而是代理類。而AopProxy是由AopProxyFactory接口生成,目前該接口只有DefaultAopProxyFactory實(shí)現(xiàn)類,其提供了兩種AopProxy,分別基于原生JDK提供的動(dòng)態(tài)代理和cgib,根據(jù)實(shí)際情況選擇。
到此這篇關(guān)于Spring源碼學(xué)習(xí)之動(dòng)態(tài)代理實(shí)現(xiàn)流程的文章就介紹到這了,更多相關(guān)Spring動(dòng)態(tài)代理實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springBoot項(xiàng)目中的static和templates文件夾的使用
本文主要介紹了springBoot項(xiàng)目中的static和templates文件夾的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07淺談Java鎖的膨脹過程以及一致性哈希對(duì)鎖膨脹的影響
本文主要介紹了Java鎖的膨脹過程以及一致性哈希對(duì)鎖膨脹的影響,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02jcl與jul?log4j1?log4j2?logback日志系統(tǒng)機(jī)制及集成原理
這篇文章主要介紹了jcl與jul?log4j1?log4j2?logback的集成原理,Apache?Commons-logging?通用日志框架與日志系統(tǒng)的機(jī)制,有需要的朋友可以借鑒參考下2022-03-03Java 實(shí)戰(zhàn)范例之線上新聞平臺(tái)系統(tǒng)的實(shí)現(xiàn)
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+jsp+jdbc+mysql實(shí)現(xiàn)一個(gè)線上新聞平臺(tái)系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11java Collection 之List學(xué)習(xí)介紹
本篇文章小編為大家介紹,java Collection 之List學(xué)習(xí)介紹。需要的朋友參考下2013-04-04Spring MVC返回的json去除根節(jié)點(diǎn)名稱的方法
這篇文章主要介紹了Spring MVC返回的json去除根節(jié)點(diǎn)名稱的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09