SpringBoot Environment使用


在上一篇中,我們的類加載器使用environment獲取一些屬性,如下圖

 

 下面我們介紹下environment的使用

1、進入啟動方法run,定位到prepareEnvironment方法

 

 

 

2、進到prepareEnvironment方法

 

 

 

3、進入getOrCreateEnvironment方法。實例化了StandardServletEnvironment

 

 

 

進入父類AbstractEnvironment的構造函數

 

 

 

1)、進入customizePropertySources方法。

增加servletConfigInitParams屬性源servletContextInitParams屬性源,添加jndi屬性源

然后調用父類的super.customizePropertySources(propertySources);

    protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
        propertySources.addLast(new StubPropertySource("servletContextInitParams"));
        if(JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
            propertySources.addLast(new JndiPropertySource("jndiProperties"));
        }

        super.customizePropertySources(propertySources);
    }

  

2)、進入customizePropertySources,增加兩個屬性源(系統屬性源和系統環境屬性源

	protected void customizePropertySources(MutablePropertySources propertySources) {
		propertySources.addLast(
				new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
		propertySources.addLast(
				new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

 里面getSystemProperties方法,主要有Java的版本號,Java虛擬機名稱等

 

 

 

4、然后回到configureEnvironment方法

	protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
		if (this.addConversionService) {
			ConversionService conversionService = ApplicationConversionService.getSharedInstance();
			environment.setConversionService((ConfigurableConversionService) conversionService);
		}
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

  

1) 進入configurePropertySources(environment, args);

	protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
		}
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(
						new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

  這個方法主要是添加defaultProperties默認屬性源(sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));

)和命令屬性源sources.addFirst(new SimpleCommandLinePropertySource(args));

進入SimpleCommandLinePropertySource的構造函數

	public SimpleCommandLinePropertySource(String... args) {
		super(new SimpleCommandLineArgsParser().parse(args));
	}

  里面調用了parse函數。命令的定義是我們前面介紹過的。解析命令的時候,判斷是否以“--”開頭

 

 

 

2) 進入configureProfiles。profile我們后面在進行介紹  SpringBoot Profile源碼介紹

	protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
		environment.getActiveProfiles(); // ensure they are initialized
		// But these ones should go first (last wins in a property key clash)
		Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
		environment.setActiveProfiles(StringUtils.toStringArray(profiles));
	}

  

3、 listeners.environmentPrepared(environment)

發布environmentPrepared事件,這里就是監聽器的實現。進入environmentPrepared方法

	public void environmentPrepared(ConfigurableEnvironment environment) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.environmentPrepared(environment);
		}
	}

 進入listener.environmentPrepared(environment);里面調用廣播器廣播一個事件

	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}

 進入廣播事件方法。

	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

  在此方法中,獲得對該事件感興趣的監聽器,遍歷監聽器,調用invokeListener方法。

 

監聽器的部分在前面已經介紹過了,這里我們主要看下監聽器都做了什么?

進入doInvokeListener方法

	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

  

然后進入listener.onApplicationEvent(event);方法

 

 

 然后進入onApplicationEnvironmentPreparedEvent方法

 

 

 方法loadPostProcessors是獲得屬性文件中對該監聽器的實現類有哪些。

	List<EnvironmentPostProcessor> loadPostProcessors() {
		return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, getClass().getClassLoader());
	}  

 該配置文件配置如下:

 

 

 

配置文件由三個EnvironmentPostProcessor,在把當前的添加進去postProcessors.add(this);就有四個了。然后依次遍歷這四個EnvironmentPostProcessor

 

 

 

我們進入其中一個EnvironmentPostProcessor,如ConfigFileApplicationListener。里面調用了addPropertySources(environment, application.getResourceLoader());

	@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
	}

  然后進入addPropertySources方法

	protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
		RandomValuePropertySource.addToEnvironment(environment);
		new Loader(environment, resourceLoader).load();
	}

  RandomValuePropertySource.addToEnvironment(environment);這個方法添加了一個隨機的屬性源

	public static void addToEnvironment(ConfigurableEnvironment environment) {
		environment.getPropertySources().addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
				new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME));
		logger.trace("RandomValuePropertySource add to Environment");
	}

  然后進入new Loader(environment, resourceLoader).load();的load方法。添加application-profile.(properties|yml)屬性集

		public void load() {
			this.profiles = new LinkedList<>();
			this.processedProfiles = new LinkedList<>();
			this.activatedProfiles = false;
			this.loaded = new LinkedHashMap<>();
			initializeProfiles();
			while (!this.profiles.isEmpty()) {
				Profile profile = this.profiles.poll();
				if (profile != null && !profile.isDefaultProfile()) {
					addProfileToEnvironment(profile.getName());
				}
				load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false));
				this.processedProfiles.add(profile);
			}
			resetEnvironmentProfiles(this.processedProfiles);
			load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
			addLoadedPropertySources();
		}

  關於profile留在后面介紹。  SpringBoot Profile源碼介紹

 

 

 

4、bindToSpringApplication(environment);

進入bindToSpringApplication方法

	protected void bindToSpringApplication(ConfigurableEnvironment environment) {
		try {
			Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
		}
		catch (Exception ex) {
			throw new IllegalStateException("Cannot bind to SpringApplication", ex);
		}
	}

  

 

5、environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,  deduceEnvironmentClass());

使用判斷convertEnvironmentIfNecessary當前環境是否是指定類型,是的話就返回。否的話再new一個環境,把值賦值到新的實例化的環境中

 

	StandardEnvironment convertEnvironmentIfNecessary(ConfigurableEnvironment environment,
			Class<? extends StandardEnvironment> type) {
		if (type.equals(environment.getClass())) {
			return (StandardEnvironment) environment;
		}
		return convertEnvironment(environment, type);
	}

	private StandardEnvironment convertEnvironment(ConfigurableEnvironment environment,
			Class<? extends StandardEnvironment> type) {
		StandardEnvironment result = createEnvironment(type);
		result.setActiveProfiles(environment.getActiveProfiles());
		result.setConversionService(environment.getConversionService());
		copyPropertySources(environment, result);
		return result;
	}

  

 

6、ConfigurationPropertySources.attach(environment); 增加configurationProperties屬性源

 

 

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM