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

詳解@ConfigurationProperties實現(xiàn)原理與實戰(zhàn)

 更新時間:2020年10月10日 09:20:45   作者:cmlbeliever  
這篇文章主要介紹了詳解@ConfigurationProperties實現(xiàn)原理與實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

在SpringBoot中,當需要獲取到配置文件數據時,除了可以用Spring自帶的@Value注解外,SpringBoot提供了一種更加方便的方式:@ConfigurationProperties。只要在bean上添加上這個注解,指定好配置文件的前綴,那么對應的配置文件數據就會自動填充到bean中。舉個栗子,現(xiàn)在有如下配置:

myconfig.name=test
myconfig.age=22
myconfig.desc=這是我的測試描述

添加對應的配置類,并添加上注解@ConfigurationProperties,指定前綴為myconfig

@Component
@ConfigurationProperties(prefix = "myconfig")
public class MyConfig {
private String name;
private Integer age;
private String desc;
  //get/set 略
  @Override
public String toString() {
	return "MyConfig [name=" + name + ", age=" + age + ", desc=" + desc + "]";
}
}

添加使用:

public static void main(String[] args) throws Exception {
	SpringApplication springApplication = new SpringApplication(Application.class);
	// 非web環(huán)境
	springApplication.setWebEnvironment(false);
	ConfigurableApplicationContext application = springApplication.run(args);

	MyConfig config = application.getBean(MyConfig.class);
	log.info(config.toString());
	application.close();
}

可以看到輸出log

com.cml.chat.lesson.lesson3.Application - MyConfig [name=test, age=22, desc=這是我的測試描述]

對應的屬性都注入了配置中的值,而且不需要其他操作。是不是非常神奇?那么下面來剖析下@ConfigurationProperties到底做了啥?

首先進入@ConfigurationProperties源碼中,可以看到如下注釋提示:

enter image description here

See Also 中給我們推薦了ConfigurationPropertiesBindingPostProcessor,EnableConfigurationProperties兩個類,EnableConfigurationProperties先放到一邊,因為后面的文章中會詳解EnableXX框架的實現(xiàn)原理,這里就先略過。那么重點來看看ConfigurationPropertiesBindingPostProcessor,光看類名是不是很親切?不知上篇文章中講的BeanPostProcessor還有印象沒,沒有的話趕緊回頭看看哦。

ConfigurationPropertiesBindingPostProcessor
一看就知道和BeanPostProcessor有扯不開的關系,進入源碼可以看到,該類實現(xiàn)的BeanPostProcessor和其他多個接口:

public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor,
	BeanFactoryAware, EnvironmentAware, ApplicationContextAware, InitializingBean,
	DisposableBean, ApplicationListener<ContextRefreshedEvent>, PriorityOrdered 

這里是不是非常直觀,光看類的繼承關系就可以猜出大概這個類做了什么。
BeanFactoryAware,EnvironmentAware,ApplicationContextAware是Spring提供的獲取Spring上下文中指定對象的方法而且優(yōu)先于BeanPostProcessor調用,至于如何工作的后面的文章會進行詳解,這里只要先知道下作用就可以了。
此類同樣實現(xiàn)了InitializingBean接口,從上篇文章中已經知道了InitializingBean是在BeanPostProcessor.postProcessBeforeInitialization之后調用,那么postProcessBeforeInitialization目前就是我們需要關注的重要入口方法。

先上源碼看看:

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
		throws BeansException {
	//直接通過查找添加了ConfigurationProperties注解的的類
	ConfigurationProperties annotation = AnnotationUtils
			.findAnnotation(bean.getClass(), ConfigurationProperties.class);
	if (annotation != null) {
		postProcessBeforeInitialization(bean, beanName, annotation);
	}
	//查找使用工廠bean中是否有ConfigurationProperties注解
	annotation = this.beans.findFactoryAnnotation(beanName,
			ConfigurationProperties.class);
	if (annotation != null) {
		postProcessBeforeInitialization(bean, beanName, annotation);
	}
	return bean;
}

private void postProcessBeforeInitialization(Object bean, String beanName,
		ConfigurationProperties annotation) {
	Object target = bean;
	PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
			target);
	factory.setPropertySources(this.propertySources);
	factory.setValidator(determineValidator(bean));
	// If no explicit conversion service is provided we add one so that (at least)
	// comma-separated arrays of convertibles can be bound automatically
	factory.setConversionService(this.conversionService == null
			? getDefaultConversionService() : this.conversionService);
	if (annotation != null) {
		factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
		factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
		factory.setExceptionIfInvalid(annotation.exceptionIfInvalid());
		factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties());
		if (StringUtils.hasLength(annotation.prefix())) {
			factory.setTargetName(annotation.prefix());
		}
	}
	try {
		factory.bindPropertiesToTarget();
	}
	catch (Exception ex) {
		String targetClass = ClassUtils.getShortName(target.getClass());
		throw new BeanCreationException(beanName, "Could not bind properties to "
				+ targetClass + " (" + getAnnotationDetails(annotation) + ")", ex);
	}
}

在postProcessBeforeInitialization方法中,會先去找所有添加了ConfigurationProperties注解的類對象,找到后調用postProcessBeforeInitialization進行屬性數據裝配。

那么現(xiàn)在可以將實現(xiàn)拆分成如何尋找和如何裝配兩部分來說明,首先先看下如何查找到ConfigurationProperties注解類。

查找ConfigurationProperties

在postProcessBeforeInitialization方法中先通過AnnotationUtils查找類是否添加了@ConfigurationProperties注解,然后再通過 this.beans.findFactoryAnnotation(beanName,
ConfigurationProperties.class);繼續(xù)查找,下面詳解這兩步查找的作用。

AnnotationUtils

AnnotationUtils.findAnnotation(bean.getClass(),ConfigurationProperties.class);這個是Spring中常用的工具類了,通過反射的方式獲取類上的注解,如果此類添加了注解@ConfigurationProperties那么這個方法會返回這個注解對象和類上配置的注解屬性。

beans.findFactoryAnnotation

這里的beans是ConfigurationBeanFactoryMetaData對象。在Spring中,可以以工廠bean的方式添加bean,這個類的作用就是在工程bean中找到@ConfigurationProperties注解。下面分析下實現(xiàn)過程:

ConfigurationBeanFactoryMetaData

public class ConfigurationBeanFactoryMetaData implements BeanFactoryPostProcessor {

private ConfigurableListableBeanFactory beanFactory;

private Map<String, MetaData> beans = new HashMap<String, MetaData>();

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
		throws BeansException {
	this.beanFactory = beanFactory;
 //迭代所有的bean定義,找出那些是工廠bean的對象添加到beans中
	for (String name : beanFactory.getBeanDefinitionNames()) {
		BeanDefinition definition = beanFactory.getBeanDefinition(name);
		String method = definition.getFactoryMethodName();
		String bean = definition.getFactoryBeanName();
		if (method != null && bean != null) {
			this.beans.put(name, new MetaData(bean, method));
		}
	}
}

public <A extends Annotation> Map<String, Object> getBeansWithFactoryAnnotation(
		Class<A> type) {
	Map<String, Object> result = new HashMap<String, Object>();
	for (String name : this.beans.keySet()) {
		if (findFactoryAnnotation(name, type) != null) {
			result.put(name, this.beanFactory.getBean(name));
		}
	}
	return result;
}

public <A extends Annotation> A findFactoryAnnotation(String beanName,
		Class<A> type) {
	Method method = findFactoryMethod(beanName);
	return (method == null ? null : AnnotationUtils.findAnnotation(method, type));
}

//略...
	
private static class MetaData {
	private String bean;
	private String method;
  //構造方法和其他方法略...
}

}

通過以上代碼可以得出ConfigurationBeanFactoryMetaData的工作機制,通過實現(xiàn)BeanFactoryPostProcessor,在回調方法postProcessBeanFactory中,查找出所有通過工廠bean實現(xiàn)的對象,并將其保存到beans map中,通過方法findFactoryAnnotation可以查詢到工廠bean中是否添加了對應的注解。那么這里的功能就是查找工廠bean中有添加@ConfigurationProperties注解的類了。

屬性值注入

通過上述步驟,已經確認了當前傳入的bean是否添加了@ConfigurationProperties注解。如果添加了則下一步就需要進行屬性值注入了,核心代碼在方法postProcessBeforeInitialization中:

private void postProcessBeforeInitialization(Object bean, String beanName,
		ConfigurationProperties annotation) {
	Object target = bean;
	PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
			target);
	//重點,這里設置數據來源
	factory.setPropertySources(this.propertySources);
	factory.setValidator(determineValidator(bean));
	//設置轉換器
	factory.setConversionService(this.conversionService == null
			? getDefaultConversionService() : this.conversionService);
	if (annotation != null) {
	//將annotation中配置的屬性配置到factory中
	}
	try {
	  //這里是核心,綁定屬性值到對象中
		factory.bindPropertiesToTarget();
	}
	catch (Exception ex) {
	//拋出異常
	}
}

繼續(xù)跟進factory.bindPropertiesToTarget方法,在bindPropertiesToTarget方法中,調用的是doBindPropertiesToTarget方法:

private void doBindPropertiesToTarget() throws BindException {
	RelaxedDataBinder dataBinder 
  //略...
  //1、獲取bean中所有的屬性名稱
  Set<String> names = getNames(relaxedTargetNames);
  //2、將屬性名稱和前綴轉換為配置文件的key值
  PropertyValues propertyValues = getPropertySourcesPropertyValues(names,relaxedTargetNames);
  //3、通過上面兩個步驟找到的屬性從配置文件中獲取數據通過反射注入到bean中
	dataBinder.bind(propertyValues);
	//數據校驗
	if (this.validator != null) {
		dataBinder.validate();
	}
	//判斷數據綁定過程中是否有錯誤
	checkForBindingErrors(dataBinder);
}

上面代碼中使用dataBinder.bind方法進行屬性值賦值,源碼如下:

public void bind(PropertyValues pvs) {
	MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues) ?
			(MutablePropertyValues) pvs : new MutablePropertyValues(pvs);
	doBind(mpvs);
}
protected void doBind(MutablePropertyValues mpvs) {
	checkAllowedFields(mpvs);
	checkRequiredFields(mpvs);
	//進行賦值
	applyPropertyValues(mpvs);
}
protected void applyPropertyValues(MutablePropertyValues mpvs) {
	try {
		// Bind request parameters onto target object.
		getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
	}
	catch (PropertyBatchUpdateException ex) {
		// Use bind error processor to create FieldErrors.
		for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
			getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
		}
	}
}

經過以上步驟連續(xù)的方法調用后,最終調用的是ConfigurablePropertyAccessor.setPropertyValues使用反射進行設置屬性值,到這里就不繼續(xù)深入了。想要繼續(xù)深入了解的可以繼續(xù)閱讀源碼,到最后可以發(fā)現(xiàn)調用的是AbstractNestablePropertyAccessor.processLocalProperty中使用反射進行賦值。

上面的代碼分析非常清晰明了的解釋了如何查找@ConfigurationProperties對象和如何使用反射的方式進行賦值。

總結

在上面的步驟中我們分析了@ConfigurationProperties從篩選bean到注入屬性值的過程,整個過程的難度還不算高,沒有什么特別的難點,這又是一個非常好的BeanPostProcessor使用場景說明。
從本文中可以學習到BeanPostProcessor是在SpringBoot中運用,以及如何通過AnnotationUtils與ConfigurationBeanFactoryMetaData結合對系統(tǒng)中所有添加了指定注解的bean進行掃描。

到此這篇關于詳解@ConfigurationProperties實現(xiàn)原理與實戰(zhàn)的文章就介紹到這了,更多相關@ConfigurationProperties原理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java關鍵字之instanceof詳解

    Java關鍵字之instanceof詳解

    instanceof是Java的一個二元操作符,和==,>,<是同一類東東。由于它是由字母組成的,所以也是Java的保留關鍵字。它的作用是測試它左邊的對象是否是它右邊的類的實例,返回boolean類型的數據
    2021-11-11
  • JDK8新出Optional類的方法探索與思考分析

    JDK8新出Optional類的方法探索與思考分析

    這篇文章主要為大家介紹了JDK8新出Optional類的發(fā)方法示例探索與思考分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • java啟動jar包將日志打印到文本的簡單操作

    java啟動jar包將日志打印到文本的簡單操作

    這篇文章主要介紹了java啟動jar包將日志打印到文本的簡單操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Spring Boot實現(xiàn)文件上傳示例代碼

    Spring Boot實現(xiàn)文件上傳示例代碼

    本篇文章主要介紹了Spring Boot實現(xiàn)文件上傳示例代碼,可以實現(xiàn)單文件和多文件的上傳,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Spring Boot 整合 Shiro+Thymeleaf過程解析

    Spring Boot 整合 Shiro+Thymeleaf過程解析

    這篇文章主要介紹了Spring Boot 整合 Shiro+Thymeleaf過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • SpringBoot中實現(xiàn)Redis緩存預熱

    SpringBoot中實現(xiàn)Redis緩存預熱

    緩存預熱是一種在系統(tǒng)啟動后,但在實際使用前將數據加載到緩存中的技術,本文主要來和大家一起探討如何在Spring Boot應用程序中實現(xiàn)Redis緩存預熱,以確保系統(tǒng)在處理請求前就已經處于最佳狀態(tài),感興趣的可以了解下
    2023-11-11
  • 關于Guava緩存詳解及使用說明

    關于Guava緩存詳解及使用說明

    這篇文章主要介紹了關于Guava緩存詳解及使用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • java實現(xiàn)的RC4加密解密算法示例

    java實現(xiàn)的RC4加密解密算法示例

    這篇文章主要介紹了java實現(xiàn)的RC4加密解密算法,結合具體實例形式分析了java RC4加密解密算法的實現(xiàn)與使用技巧,需要的朋友可以參考下
    2017-06-06
  • Nacos通過RefreshScope實現(xiàn)配置自動更新的方式分享

    Nacos通過RefreshScope實現(xiàn)配置自動更新的方式分享

    這篇文章主要給大家介紹了Nacos如何通過RefreshScope實現(xiàn)配置自動更新,文中給了兩種實現(xiàn)方式供大家參考,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2023-09-09
  • springboot2.3之后hibernate-validator依賴缺失【踩坑】

    springboot2.3之后hibernate-validator依賴缺失【踩坑】

    這篇文章主要介紹了springboot2.3之后hibernate-validator依賴缺失【踩坑】,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11

最新評論

祁连县| 黎城县| 朔州市| 沙河市| 平山县| 平南县| 汨罗市| 潜江市| 库尔勒市| 南充市| 六安市| 莱州市| 东城区| 山丹县| 黄龙县| 安龙县| 达尔| 松江区| 孟州市| 商洛市| 沿河| 乌拉特中旗| 峡江县| 阳曲县| 鞍山市| 玉环县| 中超| 同心县| 桐乡市| 绥中县| 台湾省| 日喀则市| 北辰区| 遂溪县| 利川市| 股票| 民丰县| 武隆县| 遂昌县| 马边| 扶余县|