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

SpringBoot深入淺出分析初始化器

 更新時(shí)間:2022年07月15日 09:55:39   作者:lhf2112  
這篇文章主要介紹了SpringBoot初始化器的分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

如有錯(cuò)誤,望指正;

SpringBoot可以有三種方式定義初始化器,來為容器中增加自定義的對(duì)象,具體如下:

1、定義在spring.factories文件中,被SpringFactoriesLoader發(fā)現(xiàn)注冊(cè);

在resources下建立META-INF文件夾,新建spring.factories文件,添加自定義的初始化器:
org.springframework.context.ApplicationContextInitializer=com.mooc.sb2.initializer.InitializerOne

2、SpringApplication初始化完成后手動(dòng)添加;

SpringApplication springApplication = new SpringApplication(SbApplication.class);
springApplication.addInitializers(new InitializerTwo());
springApplication.run(args)

3、定義成環(huán)境變量,被DelegatingApplicationContextInitializer所發(fā)現(xiàn)注冊(cè)(優(yōu)先級(jí)最高)

application.properties中增加一項(xiàng)配置:
context.initializer.classes=com.mooc.sb2.initializer.ThirdInitializer

下面從代碼的角度,來看下這三種方式是如何加載的

對(duì)于第一種方法,可以跟進(jìn)

SpringApplication.run(SpringBootApplication.class, args);
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class<?>[] { primarySource }, args);
}

繼續(xù)進(jìn)入這個(gè)run方法:

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

還有一個(gè)run方法,我們繼續(xù)進(jìn)入:

這個(gè)run方法代碼比較長(zhǎng),這里我們關(guān)注的是這部分:

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);

我們進(jìn)入這個(gè)getSpringFactoriesInstances方法,如下:

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

我們先看這個(gè)loadFactoryNames方法,它調(diào)用了loadSpringFactories方法來獲取固定位置的配置信息:

loadSpringFactories的重點(diǎn)部分代碼如下:

        try {
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}

我們可以發(fā)現(xiàn)一個(gè)常量的定義:FACTORIES_RESOURCE_LOCATION,而它的值,就是

"META-INF/spring.factories"

這里就解釋了我們?yōu)槭裁匆约航ㄒ粋€(gè)配置文件在固定的目錄下,這樣springboot就成功讀取到了自定義的初始化器,加載到了cache中;下面我們回到SpringApplication.java中,繼續(xù)跟進(jìn)getSpringFactoriesInstances方法。

在獲取到了初始化器的全限定名后,我們繼續(xù)看createSpringFactoriesInstances方法:

	private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

主要使用了反射手段,來完成初始化器的實(shí)例化工作;在獲取了實(shí)例列表之AnnotationAwareOrderComparator.sort(instances);會(huì)將實(shí)例按照@Order的注解順序進(jìn)行排序,在這里不進(jìn)行詳述;

第二種初始化器是通過手動(dòng)添加

第三種是通過DelegatingApplicationContextInitializer的initialize方法來調(diào)用的,首先,我們先看這個(gè)方法的代碼:

	@Override
	public void initialize(ConfigurableApplicationContext context) {
		ConfigurableEnvironment environment = context.getEnvironment();
		List<Class<?>> initializerClasses = getInitializerClasses(environment);
		if (!initializerClasses.isEmpty()) {
			applyInitializerClasses(context, initializerClasses);
		}
	}

其中,我們重點(diǎn)關(guān)注getInitializerClasses()方法

	private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
		String classNames = env.getProperty(PROPERTY_NAME);
		List<Class<?>> classes = new ArrayList<>();
		if (StringUtils.hasLength(classNames)) {
			for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
				classes.add(getInitializerClass(className));
			}
		}
		return classes;
	}

這里的常量:

PROPERTY_NAME= "context.initializer.classes";

也就是我們配置文件的key,value值會(huì)被以‘,’為分界線進(jìn)行分割,來獲得每個(gè)所需的系統(tǒng)初始化器的全限定名,并通過BeanUtis工具來進(jìn)行初始化;

另:為什么DelegatingApplicationContextInitializer加載的初始化器是優(yōu)先于其他方式執(zhí)行呢?這是因?yàn)镾pringApplication的run方法中的prepareContext方法會(huì)調(diào)用applyInitializers方法,applyInitializers方法的for循環(huán)會(huì)調(diào)用getInitializers方法來加載所有的初始化器,而DelegatingApplicationContextInitializer的Order=0,因此優(yōu)先級(jí)最高,會(huì)被最先加載;

到此這篇關(guān)于SpringBoot深入淺出分析初始化器的文章就介紹到這了,更多相關(guān)SpringBoot初始化器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java反編譯工具jd-gui-osx?for?mac?M1芯片無法使用的問題及解決

    java反編譯工具jd-gui-osx?for?mac?M1芯片無法使用的問題及解決

    這篇文章主要介紹了java反編譯工具jd-gui-osx?for?mac?M1芯片無法使用的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Springboot整合SpringSecurity的完整案例詳解

    Springboot整合SpringSecurity的完整案例詳解

    Spring Security是基于Spring生態(tài)圈的,用于提供安全訪問控制解決方案的框架,Spring Security登錄認(rèn)證主要涉及兩個(gè)重要的接口 UserDetailService和UserDetails接口,本文對(duì)Springboot整合SpringSecurity過程給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2024-01-01
  • 簡(jiǎn)單了解Spring循環(huán)依賴解決過程

    簡(jiǎn)單了解Spring循環(huán)依賴解決過程

    這篇文章主要介紹了簡(jiǎn)單了解Spring循環(huán)依賴解決過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • java環(huán)境搭建教程

    java環(huán)境搭建教程

    這篇文章主要為大家詳細(xì)介紹了java環(huán)境的搭建教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • java面向?qū)ο笤O(shè)計(jì)原則之單一職責(zé)與依賴倒置原則詳解

    java面向?qū)ο笤O(shè)計(jì)原則之單一職責(zé)與依賴倒置原則詳解

    這篇文章主要介紹了java面向?qū)ο笤O(shè)計(jì)原則之單一職責(zé)與依賴倒置原則的分析詳解,有需要的朋友可以借鑒參考下,希望可以有所幫助,祝大家多多進(jìn)步早日升職加薪
    2021-10-10
  • java利用注解實(shí)現(xiàn)簡(jiǎn)單的excel數(shù)據(jù)讀取

    java利用注解實(shí)現(xiàn)簡(jiǎn)單的excel數(shù)據(jù)讀取

    這篇文章主要為大家詳細(xì)介紹了java利用注解實(shí)現(xiàn)簡(jiǎn)單的excel數(shù)據(jù)讀取,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • MyBatis中如何優(yōu)雅的使用枚舉詳解

    MyBatis中如何優(yōu)雅的使用枚舉詳解

    枚舉類型是我們?cè)陂_發(fā)中經(jīng)常遇到的一個(gè)類型,最近在學(xué)習(xí)MyBatis,但是發(fā)現(xiàn)網(wǎng)上沒有詳細(xì)介紹MyBatis如何使用枚舉的相關(guān)文章,索性就自己寫一篇,下面這篇文章主要給大家介紹了關(guān)于在MyBatis中如何優(yōu)雅的使用枚舉的相關(guān)資料,需要的朋友可以參考借鑒。
    2017-08-08
  • java并發(fā)高的情況下用ThreadLocalRandom來生成隨機(jī)數(shù)

    java并發(fā)高的情況下用ThreadLocalRandom來生成隨機(jī)數(shù)

    如果我們想要生成一個(gè)隨機(jī)數(shù),通常會(huì)使用Random類。但是在并發(fā)情況下Random生成隨機(jī)數(shù)的性能并不是很理想,本文主要介紹了java并發(fā)高的情況下用ThreadLocalRandom來生成隨機(jī)數(shù),感興趣的可以了解一下
    2022-05-05
  • IDEA2020 Plugins不能用的解決辦法及Plugins 搜索不了插件的問題

    IDEA2020 Plugins不能用的解決辦法及Plugins 搜索不了插件的問題

    這篇文章主要介紹了IDEA2020 Plugins不能用的解決辦法,文中給大家介紹了Intellij IDEA 2020.1 的Plugins 搜索不了插件,連接超時(shí)的問題,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2020-06-06
  • 一文搞懂設(shè)計(jì)模式中的單例模式

    一文搞懂設(shè)計(jì)模式中的單例模式

    這篇文章主要介紹了一文搞懂設(shè)計(jì)模式中的單例模式,單例模式是最簡(jiǎn)單的設(shè)計(jì)模式之一,屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的方式,確保只有單個(gè)對(duì)象被創(chuàng)建,需要的朋友可以參考下
    2023-08-08

最新評(píng)論