欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring的@Scope注解詳細(xì)解析

 更新時(shí)間:2023年11月24日 10:09:10   作者:baidu_25504651  
這篇文章主要介紹了Spring的@Scope注解詳細(xì)解析,@Scope注解主要作用是調(diào)節(jié)Ioc容器中的作用域,springboot?程序啟動(dòng)時(shí)會(huì)對(duì)classpath路徑下的包中的類進(jìn)行掃描,將類解析成BeanDefinition,需要的朋友可以參考下

@Scope是什么,有什么用?

@Scope注解主要作用是調(diào)節(jié)Ioc容器中的作用域,在Spring IoC容器中主要有以下五種作用域:

基本作用域:singleton(單例)、prototype(多例);Web 作用域(reqeust、session、globalsession),自定義作用域。

@Scope注解源碼解析

使用@Scope注解對(duì)象注入到IOC容器過程

(1) springboot 程序啟動(dòng)時(shí)會(huì)對(duì)classpath路徑下的包中的類進(jìn)行掃描,將類解析成BeanDefinition,在掃描完BeanDefinition后會(huì)對(duì)其進(jìn)行注冊(cè),便于后面創(chuàng)建Bean時(shí)使用

    // org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan	
    /**
	 * Perform a scan within the specified base packages,
	 * returning the registered bean definitions.
	 * <p>This method does <i>not</i> register an annotation config processor
	 * but rather leaves this up to the caller.
	 * @param basePackages the packages to check for annotated classes
	 * @return set of beans registered if any for tooling registration purposes (never {@code null})
	 */
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

(2)接著會(huì)對(duì)掃描出來的BeanDefinition處理,其中下面代碼對(duì)掃描完的Bean的作用域的代理模式進(jìn)行處理:

 
    // org.springframework.context.annotation.AnnotationConfigUtils#applyScopedProxyMode	
    static BeanDefinitionHolder applyScopedProxyMode(
            ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
        ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
        if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
            return definition;
        }
        boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
        return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
    }

上面代碼會(huì)判斷作用域的代碼模式,如果是ScopedProxyMode.NO,不進(jìn)行代理處理直接返回BeanDefinition,如果不是NO,再判斷是否是ScopedProxyMode.TARGET_CLASS,在后續(xù)邏輯中會(huì)根據(jù)此來決定是否創(chuàng)建目標(biāo)類的代理類。

// org.springframework.aop.scope.ScopedProxyUtils#createScopedProxy	
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
			BeanDefinitionRegistry registry, boolean proxyTargetClass) {
		String originalBeanName = definition.getBeanName();
		BeanDefinition targetDefinition = definition.getBeanDefinition();
		String targetBeanName = getTargetBeanName(originalBeanName);
		// Create a scoped proxy definition for the original bean name,
		// "hiding" the target bean in an internal target definition.
		RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
		proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
		proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
		proxyDefinition.setSource(definition.getSource());
		proxyDefinition.setRole(targetDefinition.getRole());
		proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
		if (proxyTargetClass) {
			targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
			// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
		}
		else {
			proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
		}
		// Copy autowire settings from original bean definition.
		proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
		proxyDefinition.setPrimary(targetDefinition.isPrimary());
		if (targetDefinition instanceof AbstractBeanDefinition) {
			proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
		}
		// The target bean should be ignored in favor of the scoped proxy.
		targetDefinition.setAutowireCandidate(false);
		targetDefinition.setPrimary(false);
		// Register the target bean as separate bean in the factory.
		registry.registerBeanDefinition(targetBeanName, targetDefinition);
		// Return the scoped proxy definition as primary bean definition
		// (potentially an inner bean).
		return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
	}

上面過程向BeanDefinitionRegistry中注入了兩個(gè)BeanDefinition分別是目標(biāo)類、目標(biāo)類的代理類(beanClass為ScopedProxyFactoryBean.class)。

最終返回BeanDefinitionHolder的beanName為目標(biāo)類名,beanClass為ScopedProxyFactoryBean.class的BeanDenifition。

return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());

其中ScopedProxyFactoryBean類實(shí)現(xiàn)了BeanFactoryAware,Aware接口由Spring在AbstractAutowireCapableBeanFactory.initializeBean(beanName, bean,mbd)方法中通過調(diào)用invokeAwareMethods(beanName, bean)方法和applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)觸發(fā)Aware方法的調(diào)用setBeanFactory方法,該方法中會(huì)創(chuàng)建一個(gè)目前類的代理類暫存在其proxy變量中。

// org.springframework.aop.scope.ScopedProxyFactoryBean#setBeanFactory
@Override
public void setBeanFactory(BeanFactory beanFactory) {
   if (!(beanFactory instanceof ConfigurableBeanFactory)) {
      throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
   }
   ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
   this.scopedTargetSource.setBeanFactory(beanFactory);
   ProxyFactory pf = new ProxyFactory();
   pf.copyFrom(this);
   pf.setTargetSource(this.scopedTargetSource);
   Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
   Class<?> beanType = beanFactory.getType(this.targetBeanName);
   if (beanType == null) {
      throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
            "': Target type could not be determined at the time of proxy creation.");
   }
   if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
      pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
   }
   // Add an introduction that implements only the methods on ScopedObject.
   ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
   pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));
   // Add the AopInfrastructureBean marker to indicate that the scoped proxy
   // itself is not subject to auto-proxying! Only its target bean is.
   pf.addInterface(AopInfrastructureBean.class);
   this.proxy = pf.getProxy(cbf.getBeanClassLoader());
}

在注入目標(biāo)對(duì)象時(shí),將會(huì)時(shí)用beanName從BeanDefinitionRegistry中取出beanclass為ScopedProxyFactoryBean.class的BeanDenifition,使用該BeanDenifition創(chuàng)建一個(gè)實(shí)例,創(chuàng)建完實(shí)例后會(huì)調(diào)用getObjectForBeanInstance方法來獲取beanInstance,如果時(shí)FactoryBean則會(huì)調(diào)用其getObject()方法。

// org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean				
// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
// org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance	
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}
		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}
		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

 目標(biāo)類會(huì)被解析成ScopedProxyFactoryBean,而ScopedProxyFactoryBean是FactoryBean,所以會(huì)調(diào)用ScopedProxyFactoryBean的getObject方法,而ScopedProxyFactoryBean的getObject方法返回的是其屬性proxy即創(chuàng)建的目標(biāo)類的代理類,

	@Override
	public Object getObject() {
		if (this.proxy == null) {
			throw new FactoryBeanNotInitializedException();
		}
		return this.proxy;
	}

到此這篇關(guān)于Spring的@Scope注解詳細(xì)解析的文章就介紹到這了,更多相關(guān)@Scope注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • idea 無法debug調(diào)試的解決方案

    idea 無法debug調(diào)試的解決方案

    這篇文章主要介紹了idea 無法debug調(diào)試的解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Spring @async方法如何添加注解實(shí)現(xiàn)異步調(diào)用

    Spring @async方法如何添加注解實(shí)現(xiàn)異步調(diào)用

    這篇文章主要介紹了Spring @async方法如何添加注解實(shí)現(xiàn)異步調(diào)用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Redis打開rdb文件常用方法詳解

    Redis打開rdb文件常用方法詳解

    這篇文章主要介紹了Redis打開rdb文件常用方法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • java通過模擬post方式提交表單實(shí)現(xiàn)圖片上傳功能實(shí)例

    java通過模擬post方式提交表單實(shí)現(xiàn)圖片上傳功能實(shí)例

    這篇文章主要介紹了java通過模擬post方式提交表單實(shí)現(xiàn)圖片上傳功能實(shí)例,涉及Java針對(duì)表單的提交操作響應(yīng)及文件傳輸?shù)南嚓P(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Java并發(fā)編程必備之Synchronized關(guān)鍵字深入解析

    Java并發(fā)編程必備之Synchronized關(guān)鍵字深入解析

    本文我們深入探索了Java中的Synchronized關(guān)鍵字,包括其互斥性和可重入性的特性,文章詳細(xì)介紹了Synchronized的三種使用方式:修飾代碼塊、修飾普通方法和修飾靜態(tài)方法,感興趣的朋友一起看看吧
    2025-04-04
  • Java多線程之 FutureTask:帶有返回值的函數(shù)定義和調(diào)用方式

    Java多線程之 FutureTask:帶有返回值的函數(shù)定義和調(diào)用方式

    這篇文章主要介紹了Java多線程之 FutureTask:帶有返回值的函數(shù)定義和調(diào)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Flink狀態(tài)和容錯(cuò)源碼解析

    Flink狀態(tài)和容錯(cuò)源碼解析

    這篇文章主要為大家介紹了Flink狀態(tài)和容錯(cuò)源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • java中Map集合的常用方法總結(jié)大全

    java中Map集合的常用方法總結(jié)大全

    開發(fā)中最常用的就是List集合和Map集合,Map集合是基于java核心類java.util中的,下面這篇文章主要給大家總結(jié)介紹了關(guān)于java中Map集合的一些常用方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • HashMap確定key的存儲(chǔ)位置的源碼分析

    HashMap確定key的存儲(chǔ)位置的源碼分析

    HashMap 作為 Java 中最常用的數(shù)據(jù)結(jié)構(gòu)之一,用于存儲(chǔ)和管理鍵值對(duì),HashMap 基于哈希函數(shù)實(shí)現(xiàn),能通過將 key 映射到特定的位置來實(shí)現(xiàn)快速存儲(chǔ)、查找和刪除數(shù)據(jù),接下來將從源碼角度分析以通俗易懂的方式向大家講解一下 HashMap 如何確定 key 的存儲(chǔ)位置的
    2023-07-07
  • Spring Boot結(jié)合IDEA自帶Maven插件如何快速切換profile

    Spring Boot結(jié)合IDEA自帶Maven插件如何快速切換profile

    IDEA是目前 Java 開發(fā)者中使用最多的開發(fā)工具,它有著簡(jiǎn)約的設(shè)計(jì)風(fēng)格,強(qiáng)大的集成工具,便利的快捷鍵,這篇文章主要介紹了Spring Boot結(jié)合IDEA自帶Maven插件快速切換profile,需要的朋友可以參考下
    2023-03-03

最新評(píng)論