最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring源碼學(xué)習(xí)之動(dòng)態(tài)代理實(shí)現(xiàn)流程

 更新時(shí)間:2021年03月28日 10:37:00   作者:黃智霖-blog  
這篇文章主要給大家介紹了關(guān)于Spring源碼學(xué)習(xí)之動(dòng)態(tài)代理實(shí)現(xiàn)流程的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

注:這里不闡述Spring和AOP的一些基本概念和用法,直接進(jìn)入正題。

流程

  Spring所管理的對(duì)象大體會(huì)經(jīng)過(guò)確定實(shí)例化對(duì)象類型、推斷構(gòu)造方法創(chuàng)建對(duì)象(實(shí)例化)、設(shè)置屬性、初始化等等步驟。在對(duì)象初始化階段,Spring為開(kāi)發(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。先來(lái)看一下它的繼承關(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,過(guò)濾可用的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)) {
						//說(shuō)明這個(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è)切面。接下來(lái)就需要進(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);
	}

  邏輯很清晰,主要就是看有沒(méi)有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é)果緩存起來(lái)。

  好了,再回到findEligibleAdvisors方法,上面代碼已經(jīng)貼了,這里就不貼了。獲取到Advisor列表之后,要從中找到能用于指定類的Advisor列表,然后返回。接下來(lái)就要為指定的對(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工廠類,來(lái)看看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是單繼承,所以只能通過(guò)接口實(shí)現(xiàn),也就限制了要使用JDK提供的動(dòng)態(tài)代理,必須要基于接口。而使用cglib基于字節(jié)碼的改造則沒(méi)有這個(gè)限制,所以Spring提供了這兩種方式,根據(jù)被代理類的實(shí)際情況來(lái)選擇。

  關(guān)于每個(gè)AopProxy是如何創(chuàng)建代理類的,這里就先不跟了~

總結(jié)

  總的來(lái)說(shuō),動(dòng)態(tài)代理是實(shí)現(xiàn)AOP的重要手段,Spring提供的動(dòng)態(tài)代理主要依靠其提供的BeanPostProcessor,也稱之為后置處理器。除了BeanPostProcessor之外,還有InstantiationAwareBeanPostProcessor(也繼承了BeanPostProcessor),它們會(huì)在bean的生命周期的特定階段被調(diào)用,以開(kāi)放給開(kāi)發(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)文章

  • 淺談JAVA實(shí)現(xiàn)選擇排序,插入排序,冒泡排序,以及兩個(gè)有序數(shù)組的合并

    淺談JAVA實(shí)現(xiàn)選擇排序,插入排序,冒泡排序,以及兩個(gè)有序數(shù)組的合并

    這篇文章主要介紹了JAVA實(shí)現(xiàn)選擇排序,插入排序,冒泡排序,以及兩個(gè)有序數(shù)組的合并,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • SpringBoot集成Caffeine緩存的實(shí)現(xiàn)步驟

    SpringBoot集成Caffeine緩存的實(shí)現(xiàn)步驟

    Caffeine cache是一個(gè)針對(duì)Java的高性能緩存庫(kù)。在本文中,我們將介紹它與Spring Boot如何一起使用。
    2021-05-05
  • 詳解Spring關(guān)于@Resource注入為null解決辦法

    詳解Spring關(guān)于@Resource注入為null解決辦法

    這篇文章主要介紹了詳解Spring關(guān)于@Resource注入為null解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • 如何使用mybatis-generator自動(dòng)生成代碼

    如何使用mybatis-generator自動(dòng)生成代碼

    這篇文章主要介紹了如何使用mybatis-generator自動(dòng)生成代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Spark Streaming算子開(kāi)發(fā)實(shí)例

    Spark Streaming算子開(kāi)發(fā)實(shí)例

    這篇文章主要介紹了Spark Streaming算子開(kāi)發(fā)實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之環(huán)形鏈表

    Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之環(huán)形鏈表

    無(wú)論是靜態(tài)鏈表還是動(dòng)態(tài)鏈表,有時(shí)在解決具體問(wèn)題時(shí),需要我們對(duì)其結(jié)構(gòu)進(jìn)行稍微地調(diào)整。比如,可以把鏈表的兩頭連接,使其成為了一個(gè)環(huán)狀鏈表,通常稱為循環(huán)鏈表
    2022-02-02
  • Java 添加文本框到PPT幻燈片過(guò)程解析

    Java 添加文本框到PPT幻燈片過(guò)程解析

    這篇文章主要介紹了Java 添加文本框到PPT幻燈片過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Intellij IDEA中一次性折疊所有Java代碼的快捷鍵設(shè)置

    Intellij IDEA中一次性折疊所有Java代碼的快捷鍵設(shè)置

    這篇文章主要介紹了Intellij IDEA中一次性折疊所有Java代碼的快捷鍵設(shè)置,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Java函數(shù)式編程(九):Comparator

    Java函數(shù)式編程(九):Comparator

    這篇文章主要介紹了Java函數(shù)式編程(九):Comparator,本文是系列文章的第9篇,其它文章請(qǐng)參閱本文底部的相關(guān)文章,需要的朋友可以參考下
    2014-09-09
  • Java_Spring之XML?的?AOP?配置

    Java_Spring之XML?的?AOP?配置

    這篇文章主要介紹了Java_Spring中基于XML的AOP配置,上篇講到的是基于注解的AOP配置,對(duì)XML感興趣的同學(xué)可以參考閱讀本文
    2023-04-04

最新評(píng)論

云林县| 花垣县| 格尔木市| 怀集县| 西青区| 密山市| 南城县| 新田县| 教育| 长子县| 鄂托克旗| 根河市| 鲜城| 平安县| 册亨县| 资中县| 常宁市| 永城市| 兰溪市| 门头沟区| 金阳县| 炎陵县| 漳州市| 沧源| 中超| 白银市| 比如县| 西华县| 红桥区| 资兴市| 离岛区| 耒阳市| 西盟| 汤阴县| 呼伦贝尔市| 乐山市| 北宁市| 开远市| 盐山县| 华容县| 沾益县|