91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中Spring @Lazy延遲注入的示例分析

發布時間:2021-09-05 17:04:04 來源:億速云 閱讀:213 作者:小新 欄目:開發技術

小編給大家分享一下Java中Spring @Lazy延遲注入的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

一、一個簡單的小例子

代碼如下:

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

很明顯要執行getLazyResolutionProxyIfNecessary方法,如果加了@Lazy注解,最終會執行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。那么所謂的執行的過程中才進行獲取真正的MyService對象是什么意思呢?

2. 使用邏輯

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

Java中Spring @Lazy延遲注入的示例分析

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

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

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

Java中Spring @Lazy延遲注入的示例分析

那么當執行方法邏輯時

Java中Spring @Lazy延遲注入的示例分析

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

Java中Spring @Lazy延遲注入的示例分析

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

總結

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

Java中Spring @Lazy延遲注入的示例分析

以上是“Java中Spring @Lazy延遲注入的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

德安县| 乐陵市| 湖州市| 沁源县| 淮北市| 永顺县| 宜兰县| 兴仁县| 县级市| 永川市| 鲁山县| 金塔县| 松溪县| 靖远县| 长岛县| 通海县| 太谷县| 永新县| 横峰县| 宕昌县| 兴国县| 宜川县| 黄大仙区| 开阳县| 封开县| 南通市| 米易县| 西宁市| 昆明市| 宁南县| 慈利县| 叙永县| 新昌县| 巴彦县| 曲阳县| 宝清县| 永川市| 盘山县| 顺义区| 梁平县| 双辽市|