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

spring @Lazy延遲注入的邏輯實(shí)現(xiàn)

 更新時(shí)間:2021年08月05日 16:14:02   作者:liangsheng_g  
有時(shí)候我們會(huì)在屬性注入的時(shí)候添加@Lazy注解實(shí)現(xiàn)延遲注入,今天咱們通過閱讀源碼來分析下原因,感興趣的可以了解一下

前言

有時(shí)候我們會(huì)在屬性注入的時(shí)候添加@Lazy注解實(shí)現(xiàn)延遲注入,今天咱們通過閱讀源碼來分析下原因

一、一個(gè)簡(jiǎn)單的小例子

代碼如下:

@Service
public class NormalService1 {

	@Autowired
	@Lazy
	private MyService myService;

	public void doSomething() {
		myService.getName();
	}
}

作用是為了進(jìn)行延遲加載,在NormalService1進(jìn)行屬性注入的時(shí)候,如果MyService還沒有生成bean也不用擔(dān)心,會(huì)注入一個(gè)代理,但是在實(shí)際運(yùn)行的時(shí)候,會(huì)獲取Spring容器中實(shí)際的MyService,在某些情況下,因?yàn)閟pring生命周期的原因,這個(gè)注解有大用。

二、源碼解讀

1. 注入

代碼如下(DefaultListableBeanFactory#resolveDependency):

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			//如果注入屬性添加了@Lazy,懶加載,此時(shí)spring會(huì)根據(jù)具體類型搞個(gè)cglib代理類
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

很明顯要執(zhí)行g(shù)etLazyResolutionProxyIfNecessary方法,如果加了@Lazy注解,最終會(huì)執(zhí)行buildLazyResolutionProxy方法

protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
		Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,
				"BeanFactory needs to be a DefaultListableBeanFactory");
		final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
		TargetSource ts = new TargetSource() {
			@Override
			public Class<?> getTargetClass() {
				return descriptor.getDependencyType();
			}
			@Override
			public boolean isStatic() {
				return false;
			}
			@Override
			public Object getTarget() {
				Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
				/**
				something valid
				**/
				return target;
			}
			@Override
			public void releaseTarget(Object target) {
			}
		};
		ProxyFactory pf = new ProxyFactory();
		pf.setTargetSource(ts);
		Class<?> dependencyType = descriptor.getDependencyType();
		if (dependencyType.isInterface()) {
			pf.addInterface(dependencyType);
		}
		return pf.getProxy(beanFactory.getBeanClassLoader());
	}

可以看到上面這段代碼,其實(shí)就是生成了一個(gè)TargetSource,然后再生成了一個(gè)代理(CGLIB或者JDK),然后作為MyService對(duì)象注入給了NormalService1。那么所謂的執(zhí)行的過程中才進(jìn)行獲取真正的MyService對(duì)象是什么意思呢?

2. 使用邏輯

本文示例代碼使用的是CGLIB代理,其實(shí)是類似的,因?yàn)樽⑷氲腗yService是個(gè)CGLIB代理對(duì)象,那么在執(zhí)行方法的時(shí)候,就會(huì)調(diào)用CglibAopProxy#DynamicAdvisedInterceptor#intercept方法

在這里插入圖片描述

那么此處其實(shí)調(diào)用的就是上面的

Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);

這個(gè)方法就不用認(rèn)真看了,主要功能就是從Spring容器中找到MyService。
在之前講@Autowired原理和@Resource注入原理的時(shí)候解釋過了,不清楚的可以看專欄里其他文章。
拿出來之后會(huì)發(fā)現(xiàn),咱們拿到的target對(duì)象還是一個(gè)CGLIB增加的對(duì)象

在這里插入圖片描述

那么當(dāng)執(zhí)行方法邏輯時(shí)

在這里插入圖片描述

由于target是CGLIB對(duì)象,會(huì)再次進(jìn)入到CglibAopProxy#DynamicAdvisedInterceptor#intercept方法。
此時(shí)拿到的target對(duì)象類型就不同了

在這里插入圖片描述

是我們代理之前的target對(duì)象,此時(shí)再次進(jìn)行invoke的時(shí)候,就會(huì)進(jìn)行動(dòng)態(tài)代理的一般邏輯,先查找該方法匹配的所有advice,然后依次調(diào)用,最終調(diào)用target本身對(duì)于方法的執(zhí)行。

總結(jié)

所以可以發(fā)現(xiàn)其實(shí)@Lazy只不過是給spring的代理對(duì)象proxy再進(jìn)行了一次proxy,只不過沒有在注入的時(shí)候,就獲取到對(duì)象,而是借用了方法invoke時(shí)通過proxy的intercept方法getTarget,然后進(jìn)行方法調(diào)用,延遲了對(duì)象的注入。之后每次調(diào)用的時(shí)候都需要從Spring容器中獲取到原生的proxy對(duì)象。

在這里插入圖片描述

到此這篇關(guān)于spring @Lazy延遲注入的邏輯實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)spring @Lazy延遲注入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Executor攔截器高級(jí)教程QueryInterceptor的規(guī)范

    Executor攔截器高級(jí)教程QueryInterceptor的規(guī)范

    今天小編就為大家分享一篇關(guān)于Executor攔截器高級(jí)教程QueryInterceptor的規(guī)范,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • SpringBoot2之PUT請(qǐng)求接收不了參數(shù)的解決方案

    SpringBoot2之PUT請(qǐng)求接收不了參數(shù)的解決方案

    這篇文章主要介紹了SpringBoot2之PUT請(qǐng)求接收不了參數(shù)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • SpringBoot對(duì)SSL的支持實(shí)現(xiàn)

    SpringBoot對(duì)SSL的支持實(shí)現(xiàn)

    本文主要介紹了SpringBoot對(duì)SSL的支持實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • Spring整合SpringMVC與Mybatis(SSM)實(shí)現(xiàn)完整登錄功能流程詳解

    Spring整合SpringMVC與Mybatis(SSM)實(shí)現(xiàn)完整登錄功能流程詳解

    開學(xué)學(xué)校開始講servlet 后期要求做一個(gè)登錄功能,這個(gè)使用SSM先只做個(gè)簡(jiǎn)單的只帶登錄功能的,且項(xiàng)目使用了MyBatis-Plus來簡(jiǎn)化開發(fā)流程。看情況決定要不要升級(jí)功能或者換個(gè)寫法
    2022-09-09
  • SpringSecurity微服務(wù)實(shí)戰(zhàn)之公共模塊詳解

    SpringSecurity微服務(wù)實(shí)戰(zhàn)之公共模塊詳解

    這篇文章主要為大家介紹了SpringSecurity微服務(wù)實(shí)戰(zhàn)之公共模塊詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • java中“==“和equals()的區(qū)別詳解

    java中“==“和equals()的區(qū)別詳解

    這篇文章主要給大家介紹了關(guān)于java中“==“和equals()區(qū)別的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 解決springboot啟動(dòng)Logback報(bào)錯(cuò)ERROR in ch.qos.logback.classic.joran.action.ContextNameAction - Failed to rena

    解決springboot啟動(dòng)Logback報(bào)錯(cuò)ERROR in ch.qos.logback.cla

    這篇文章主要介紹了解決springboot啟動(dòng)Logback報(bào)錯(cuò)ERROR in ch.qos.logback.classic.joran.action.ContextNameAction - Failed to rena問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 分析ABA問題的本質(zhì)及其解決辦法

    分析ABA問題的本質(zhì)及其解決辦法

    CAS的全稱是compare and swap,它是java同步類的基礎(chǔ),java.util.concurrent中的同步類基本上都是使用CAS來實(shí)現(xiàn)其原子性的。本文將介紹ABA問題的本質(zhì)及其解決辦法。
    2021-06-06
  • java中String.matches方法使用

    java中String.matches方法使用

    String.matches()方法用于檢測(cè)字符串是否符合特定的正則表達(dá)式,詳細(xì)介紹了如何使用String.matches()配合不同的正則表達(dá)式來匹配各種特定格式的字符串,感興趣的可以了解一下
    2024-09-09
  • Spring很常用的@Conditional注解的使用場(chǎng)景和源碼解析

    Spring很常用的@Conditional注解的使用場(chǎng)景和源碼解析

    今天要分享的是Spring的注解@Conditional,@Conditional是一個(gè)條件注解,它的作用是判斷Bean是否滿足條件,本文詳細(xì)介紹了@Conditional注解的使用場(chǎng)景和源碼,需要的朋友可以參考一下
    2023-04-04

最新評(píng)論

曲松县| 巴东县| 英吉沙县| 安仁县| 潼关县| 兴安县| 新余市| 微山县| 合川市| 竹山县| 乡城县| 岑巩县| 甘谷县| 都安| 准格尔旗| 黔东| 上饶县| 洪洞县| 岐山县| 永定县| 库车县| 汕头市| 灵石县| 毕节市| 任丘市| 合山市| 区。| 和平县| 大洼县| 子洲县| 兖州市| 元阳县| 敦化市| 吉木萨尔县| 乐清市| 浦江县| 丰顺县| 镇安县| 哈巴河县| 通海县| 大厂|