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

spring中自動注入注解的實現(xiàn)方式

 更新時間:2024年09月19日 09:18:15   作者:潭影空人心  
在Spring框架中,AutowiredAnnotationBeanPostProcessor負(fù)責(zé)處理@Autowired和@Value注解,實現(xiàn)依賴注入,首先通過TypeMappedAnnotations獲取注解,并根據(jù)注解屬性構(gòu)建InjectionMetadata,存入緩存

在前面的文章中,我們介紹過,基于注解的包掃描模式下,會默認(rèn)注冊一系列的后置處理器,其中,就包含一個 AutowiredAnnotationBeanPostProcessor,這個處理器默認(rèn)就會處理 @Autowired@Value 注解。

類結(jié)構(gòu)

從圖中可知,這是一個 MergedBeanDefinitionPostProcessor 實現(xiàn)類,所以會在每一個實例對象創(chuàng)建時,當(dāng)實例化結(jié)束,還未提前暴露時,對實例對象進行處理。

// AutowiredAnnotationBeanPostProcessor
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
	metadata.checkConfigMembers(beanDefinition);
}

獲取注解

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	// 確定緩存 key
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// 從緩存獲取 InjectionMetadata
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	// metadata 為 null,表示需要刷新
	if (InjectionMetadata.needsRefresh(metadata, clazz)) {
		synchronized (this.injectionMetadataCache) {
			metadata = this.injectionMetadataCache.get(cacheKey);
			if (InjectionMetadata.needsRefresh(metadata, clazz)) {
				if (metadata != null) {
					metadata.clear(pvs);
				}
				// 創(chuàng)建 metadata
				metadata = buildAutowiringMetadata(clazz);
				// 放入緩存
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
	return metadata;
}
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
	// autowiredAnnotationTypes 兩種類型 @Autowired/@Value
	if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
		return InjectionMetadata.EMPTY;
	}

	List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
	Class<?> targetClass = clazz;

	do {
		final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
		
		// 處理 Field 上注解
		ReflectionUtils.doWithLocalFields(targetClass, field -> {
			MergedAnnotation<?> ann = findAutowiredAnnotation(field);
			if (ann != null) {
				// static 不支持注入
				if (Modifier.isStatic(field.getModifiers())) {
					if (logger.isInfoEnabled()) {
						logger.info("Autowired annotation is not supported on static fields: " + field);
					}
					return;
				}
				// 默認(rèn) true
				boolean required = determineRequiredStatus(ann);
				currElements.add(new AutowiredFieldElement(field, required));
			}
		});

		// 處理 Method 上注解
		ReflectionUtils.doWithLocalMethods(targetClass, method -> {
			Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
			if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
				return;
			}
			MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
			if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
				if (Modifier.isStatic(method.getModifiers())) {
					if (logger.isInfoEnabled()) {
						logger.info("Autowired annotation is not supported on static methods: " + method);
					}
					return;
				}
				if (method.getParameterCount() == 0) {
					if (logger.isInfoEnabled()) {
						logger.info("Autowired annotation should only be used on methods with parameters: " +
								method);
					}
				}
				boolean required = determineRequiredStatus(ann);
                // Method 比 Field 多了 PropertyDescriptor
				PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
				currElements.add(new AutowiredMethodElement(method, required, pd));
			}
		});

		elements.addAll(0, currElements);
		targetClass = targetClass.getSuperclass();
	}
	while (targetClass != null && targetClass != Object.class);

	return InjectionMetadata.forElements(elements, clazz);
}

@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
	// TypeMappedAnnotations
	MergedAnnotations annotations = MergedAnnotations.from(ao);
	for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
		// 獲取指定 type 對應(yīng)的 TypeMappedAnnotation,存在,將對應(yīng)的 TypeMappedAnnotation 返回
		MergedAnnotation<?> annotation = annotations.get(type);
		if (annotation.isPresent()) {
			return annotation;
		}
	}
	return null;
}

可以看到,獲取當(dāng)前類及其父類中 Field 或 Method 上定義的注解,此時封裝為 TypeMappedAnnotations,接著獲取指定注入注解類型對應(yīng)的 TypeMappedAnnotation,存在,返回 TypeMappedAnnotation,從中獲取注解屬性 "required" 對應(yīng)的值,默認(rèn) true,之后將 Field 或 Method 封裝成 InjectionMetadata.InjectedElement,加入 elements 集合,最后包裝成 InjectionMetadata,放入 AutowiredAnnotationBeanPostProcessor 中 injectionMetadataCache 緩存。

有一點要注意,就是 Method 注入時,雖然獲取了 pd,但測試中 pd 為 null,也不影響注入,由此也說明注入的方法不一定必須是 setter 或 getter 方法。

注入

實例化完 bean 之后,進行屬性填充,執(zhí)行 AbstractAutowireCapableBeanFactory#populateBean,此時會調(diào)用 InstantiationAwareBeanPostProcessor#postProcessProperties,AutowiredAnnotationBeanPostProcessor 實現(xiàn)了這個方法。

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

findAutowiringMetadata 前面已經(jīng)介紹過了,此時會直接從緩存獲取到 InjectionMetadata。

// InjectionMetadata
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> checkedElements = this.checkedElements;
	Collection<InjectedElement> elementsToIterate =
			(checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		for (InjectedElement element : elementsToIterate) {
			element.inject(target, beanName, pvs);
		}
	}
}

遍歷,對每個 InjectedElement,調(diào)用 inject 方法。從上面介紹可知,InjectedElement 共兩種,分別是針對 Field 的 AutowiredFieldElement,以及針對 Method 的 AutowiredMethodElement。下面分別介紹。

Field 注入

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Field field = (Field) this.member;
	Object value;
	// false
	if (this.cached) {
		try {
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Unexpected removal of target bean for cached argument -> re-resolve
			value = resolveFieldValue(field, bean, beanName);
		}
	}
	else {
		value = resolveFieldValue(field, bean, beanName);
	}
	if (value != null) {
        // 反射注入值
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
	DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
	desc.setContainingClass(bean.getClass());
	Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
	Assert.state(beanFactory != null, "No BeanFactory available");
	// 創(chuàng)建了一個 SimpleTypeConverter 作為 typeConverter
	TypeConverter typeConverter = beanFactory.getTypeConverter();
	Object value;
	try {
		// 解析依賴,對于基本類型,解析后經(jīng)過轉(zhuǎn)換返回包裝類型
		value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
	}
	catch (BeansException ex) {
		throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
	}
	synchronized (this) {
		if (!this.cached) {
			Object cachedFieldValue = null;
			if (value != null || this.required) {
				cachedFieldValue = desc;
				registerDependentBeans(beanName, autowiredBeanNames);
				if (autowiredBeanNames.size() == 1) {
					String autowiredBeanName = autowiredBeanNames.iterator().next();
					if (beanFactory.containsBean(autowiredBeanName) &&
							beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
						cachedFieldValue = new ShortcutDependencyDescriptor(
								desc, autowiredBeanName, field.getType());
					}
				}
			}
			this.cachedFieldValue = cachedFieldValue;
			this.cached = true;
		}
	}
	return value;
}

邏輯比較簡單,解析出注入的值,接著反射注入值。

Method 注入

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	if (checkPropertySkipping(pvs)) {
		return;
	}
	Method method = (Method) this.member;
	Object[] arguments;
	if (this.cached) {
		try {
			arguments = resolveCachedArguments(beanName);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Unexpected removal of target bean for cached argument -> re-resolve
			arguments = resolveMethodArguments(method, bean, beanName);
		}
	}
	else {
		// 解析參數(shù)
		arguments = resolveMethodArguments(method, bean, beanName);
	}
	if (arguments != null) {
		try {
			// 反射調(diào)用方法,注入屬性
			ReflectionUtils.makeAccessible(method);
			method.invoke(bean, arguments);
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
	}
}
@Nullable
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
	int argumentCount = method.getParameterCount();
	Object[] arguments = new Object[argumentCount];
	DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
	Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
	Assert.state(beanFactory != null, "No BeanFactory available");
	TypeConverter typeConverter = beanFactory.getTypeConverter();
	// 解析每一個參數(shù)
	for (int i = 0; i < arguments.length; i++) {
		// 封裝 MethodParameter
		MethodParameter methodParam = new MethodParameter(method, i);
		// 封裝 DependencyDescriptor
		DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
		currDesc.setContainingClass(bean.getClass());
		descriptors[i] = currDesc;
		try {
			// 解析依賴,required 默認(rèn) true,遇見無法解析的直接拋出異常
			Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
			if (arg == null && !this.required) {
				arguments = null;
				break;
			}
			// 構(gòu)造參數(shù)
			arguments[i] = arg;
		}
		catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
		}
	}
	synchronized (this) {
		if (!this.cached) {
			if (arguments != null) {
				DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
				registerDependentBeans(beanName, autowiredBeans);
				if (autowiredBeans.size() == argumentCount) {
					Iterator<String> it = autowiredBeans.iterator();
					Class<?>[] paramTypes = method.getParameterTypes();
					for (int i = 0; i < paramTypes.length; i++) {
						String autowiredBeanName = it.next();
						if (beanFactory.containsBean(autowiredBeanName) &&
								beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
							cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
									descriptors[i], autowiredBeanName, paramTypes[i]);
						}
					}
				}
				this.cachedMethodArguments = cachedMethodArguments;
			}
			else {
				this.cachedMethodArguments = null;
			}
			this.cached = true;
		}
	}
	return arguments;
}

可以看到,不管是 Field 注入還是 Method 注入,都是先封裝出一個 DependencyDescriptor,接著執(zhí)行 beanFactory.resolveDependency 進行依賴的解析,不同點在于 Field 解析完就返回了,而 Method 解析完是為了構(gòu)造出參數(shù)數(shù)組。

之后,不管是 Field 注入,還是 Method 注入,都是利用反射完成注入。這也說明,Method 注入時,只要能正常的封裝出參數(shù)數(shù)組,就能完成屬性或字段注入。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • mybatis中返回主鍵一直為1的問題

    mybatis中返回主鍵一直為1的問題

    這篇文章主要介紹了mybatis中返回主鍵一直為1的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java寫哈希表的完整實例代碼

    Java寫哈希表的完整實例代碼

    Java中的哈希表是數(shù)據(jù)結(jié)構(gòu)中的一個重要組成部分,用于高效存儲和查找數(shù)據(jù),這篇文章主要介紹了Java寫哈希表的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2026-03-03
  • SpringBoot項目啟動報錯:命令行太長解決的兩種解決方法

    SpringBoot項目啟動報錯:命令行太長解決的兩種解決方法

    SpringBoot項目啟動時可能會遇到命令行太長的錯誤,本文介紹兩種解決方法修改.idea\workspace.xml文件和執(zhí)行maven的clean命令或重啟IDEA,這些操作可以有效解決啟動問題,需要的朋友可以參考下
    2024-10-10
  • 基于maven搭建一個ssm的web項目的詳細(xì)圖文教程

    基于maven搭建一個ssm的web項目的詳細(xì)圖文教程

    這篇文章主要介紹了基于maven搭建一個ssm的web項目的詳細(xì)教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • 分享Spring Boot 3.x微服務(wù)升級歷程

    分享Spring Boot 3.x微服務(wù)升級歷程

    Spring Boot 3.0.0 GA版已經(jīng)發(fā)布,好多人也開始嘗試升級,有人測試升級后,啟動速度確實快了不少,這篇文章主要介紹了Spring Boot 3.x微服務(wù)升級經(jīng)歷,需要的朋友可以參考下
    2022-12-12
  • spring?boot集成redisson的最佳實踐示例

    spring?boot集成redisson的最佳實踐示例

    這篇文章主要為大家介紹了spring?boot集成redisson的最佳實踐示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-03-03
  • Mybatis 中Mapper使用package方式配置報錯的解決方案

    Mybatis 中Mapper使用package方式配置報錯的解決方案

    這篇文章主要介紹了Mybatis 中Mapper使用package方式配置報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 深入理解DevOps+微服務(wù)框架

    深入理解DevOps+微服務(wù)框架

    這篇文章主要介紹了深入理解DevOps+微服務(wù),主要包括DevOps 的三大支柱之中,即人(People)、流程(Process)和平臺(Platform)的知識講解,需要的朋友可以參考下
    2022-05-05
  • SpringCloud OpenFeign超時控制示例詳解

    SpringCloud OpenFeign超時控制示例詳解

    在Spring Cloud中使用OpenFeign時,可以通過配置來控制請求的超時時間,這篇文章主要介紹了SpringCloud OpenFeign超時控制,需要的朋友可以參考下
    2024-05-05
  • Java封裝統(tǒng)一的Result Model案例

    Java封裝統(tǒng)一的Result Model案例

    這篇文章主要介紹了Java封裝統(tǒng)一的Result Model案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08

最新評論

沙河市| 郓城县| 迭部县| 高陵县| 乌拉特中旗| 东台市| 桂东县| 邵阳市| 友谊县| 河北区| 内江市| 龙岩市| 扶余县| 多伦县| 曲松县| 上杭县| 库车县| 荆州市| 杨浦区| 昌宁县| 嵊州市| 天祝| 上蔡县| 开封县| 昭苏县| 眉山市| 琼中| 小金县| 措美县| 丰原市| 嘉鱼县| 潼南县| 黄陵县| 巍山| 林西县| 沭阳县| 郓城县| 瑞昌市| 荣成市| 德安县| 兰考县|