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

Java Spring @Lazy延遲注入源碼案例詳解

 更新時間:2021年09月02日 09:28:51   作者:liangsheng_g  
這篇文章主要介紹了Java Spring @Lazy延遲注入源碼案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下

前言

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

一、一個簡單的小例子

代碼如下:

@Service
public class NormalService1 {

	@Autowired
	@Lazy
	private MyService myService;

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

作用是為了進行延遲加載,在NormalService1進行屬性注入的時候,如果MyService還沒有生成bean也不用擔心,會注入一個代理,但是在實際運行的時候,會獲取Spring容器中實際的MyService,在某些情況下,因為spring生命周期的原因,這個注解有大用。

二、源碼解讀

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,懶加載,此時spring會根據(jù)具體類型搞個cglib代理類
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

很明顯要執(zhí)行getLazyResolutionProxyIfNecessary方法,如果加了@Lazy注解,最終會執(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());
	}

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

2. 使用邏輯

本文示例代碼使用的是CGLIB代理,其實是類似的,因為注入的MyService是個CGLIB代理對象,那么在執(zhí)行方法的時候,就會調用CglibAopProxy#DynamicAdvisedInterceptor#intercept方法

在這里插入圖片描述

那么此處其實調用的就是上面的

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

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

在這里插入圖片描述

那么當執(zhí)行方法邏輯時

在這里插入圖片描述

由于target是CGLIB對象,會再次進入到CglibAopProxy#DynamicAdvisedInterceptor#intercept方法。
此時拿到的target對象類型就不同了

在這里插入圖片描述

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

總結

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

在這里插入圖片描述

到此這篇關于Java Spring @Lazy延遲注入源碼案例詳解的文章就介紹到這了,更多相關Java Spring @Lazy延遲注入源碼內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot項目中通過@Value給參數(shù)賦值失敗的解決方案

    SpringBoot項目中通過@Value給參數(shù)賦值失敗的解決方案

    springboot項目中通過@Value給屬性附值失敗,給參數(shù)賦值失敗,打印為空值,文中通過代碼示例給大家介紹的非常詳細,對大家解決問題有一定的幫助,需要的朋友可以參考下
    2024-04-04
  • 解決Maven項目本地公共common包緩存問題

    解決Maven項目本地公共common包緩存問題

    這篇文章主要介紹了解決Maven項目本地公共common包緩存問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 解決@RequestMapping和@FeignClient放在同一個接口上遇到的坑

    解決@RequestMapping和@FeignClient放在同一個接口上遇到的坑

    這篇文章主要介紹了解決@RequestMapping和@FeignClient放在同一個接口上遇到的坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Layui 后臺加載菜單欄名稱以及url的例子

    Layui 后臺加載菜單欄名稱以及url的例子

    今天小編就為大家分享一篇Layui 后臺加載菜單欄名稱以及url的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • Java編程實現(xiàn)漢字按字母順序排序的方法示例

    Java編程實現(xiàn)漢字按字母順序排序的方法示例

    這篇文章主要介紹了Java編程實現(xiàn)漢字按字母順序排序的方法,結合具體實例形式分析了java編碼轉換及字母排序相關操作技巧,需要的朋友可以參考下
    2017-07-07
  • 詳解Spring Cloud Finchley版中Consul多實例注冊的問題處理

    詳解Spring Cloud Finchley版中Consul多實例注冊的問題處理

    這篇文章主要介紹了詳解Spring Cloud Finchley版中Consul多實例注冊的問題處理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • SpringBoot?將配置文件掛到?jar?包外面的操作方法

    SpringBoot?將配置文件掛到?jar?包外面的操作方法

    在 SpringBoot 中,可以將配置文件放在 jar 包外面,這樣可以方便地修改配置而不需要重新打包和部署,這篇文章主要介紹了SpringBoot?如何將配置文件掛到?jar?包外面,需要的朋友可以參考下
    2023-03-03
  • java中List接口的方法詳解

    java中List接口的方法詳解

    這篇文章主要介紹了java中List接口的方法詳解,List接口是繼承Collection接口,所以Collection集合中有的方法,List集合也繼承過來,本文主要介紹一下list下的方法,需要的朋友可以參考下
    2023-10-10
  • Java 十大排序算法之希爾排序刨析

    Java 十大排序算法之希爾排序刨析

    希爾排序是希爾(Donald Shell)于1959年提出的一種排序算法。希爾排序也是一種插入排序,它是簡單插入排序經過改進之后的一個更高效的版本,也稱為縮小增量排序,同時該算法是沖破O(n2)的第一批算法之一。本文會以圖解的方式詳細介紹希爾排序的基本思想及其代碼實現(xiàn)
    2021-11-11
  • java 設計模型之單例模式詳解

    java 設計模型之單例模式詳解

    本文主要介紹了java 單例模式,單例對象(Singleton)是一種常用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在,希望能幫助有需要的同學
    2016-07-07

最新評論

栖霞市| 垫江县| 朝阳市| 云浮市| 广西| 哈密市| 赤壁市| 荔浦县| 达拉特旗| 岳阳县| 荣成市| 楚雄市| 文化| 阳山县| 阿拉善盟| 阆中市| 麦盖提县| 射阳县| 宿松县| 颍上县| 宁德市| 醴陵市| 米泉市| 三穗县| 汝城县| 都匀市| 朝阳市| 永寿县| 韶关市| 洪湖市| 莱芜市| 莱州市| 溆浦县| 黔西| 扬州市| 昆山市| 阳东县| 古丈县| 南通市| 平泉县| 宁波市|