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属性源

 

  

 
原文地址:https://www.cnblogs.com/linlf03/p/12386371.html