日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot基础-Environment解析

發(fā)布時間:2023/12/16 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot基础-Environment解析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

獲取屬性源碼跟蹤解析

入口方法

@Component public class EnvironmentDebugger implements CommandLineRunner, EnvironmentAware {private Environment environment;@Overridepublic void run(String... args) throws Exception {String study2 = environment.getProperty("study2");}@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;} }

實現(xiàn)EnvironmentAware 接口,獲取Environment對象
實現(xiàn)CommandLineRunner接口,在容器啟動完成后,獲取key的值,作為源碼跟蹤的入口

源碼跟蹤

根據(jù)入口environment.getProperty,一直點進入org.springframework.core.env.PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class, boolean),可以看到最基礎(chǔ)的實現(xiàn)

@Nullable protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {if (this.propertySources != null) {for (PropertySource<?> propertySource : this.propertySources) {if (logger.isTraceEnabled()) {logger.trace("Searching for key '" + key + "' in PropertySource '" +propertySource.getName() + "'");}Object value = propertySource.getProperty(key);if (value != null) {if (resolveNestedPlaceholders && value instanceof String) {value = resolveNestedPlaceholders((String) value);}logKeyFound(key, propertySource, value);return convertValueIfNecessary(value, targetValueType);}}}if (logger.isTraceEnabled()) {logger.trace("Could not find key '" + key + "' in any property source");}return null; }

方法中可以看出通過key獲取屬性值,遍歷propertySources中存放的PropertySource,并且從中依次取出屬性,如果所有都沒有取到,則返回NULL


可以看出propertySources中共存在7中類型的屬性,可以找到我們設(shè)置的默認(rèn)屬性,并且已鍵值對存放數(shù)據(jù)

PropertySource源碼

public abstract class PropertySource<T> {protected final Log logger = LogFactory.getLog(getClass());protected final String name;protected final T source; }

source為存放屬性的具體實現(xiàn)

通過獲取屬性可以看出所有的屬性都存放在:propertySources中,只需要搞懂spring容器在啟動的時候是如何裝載自定義的屬性進propertySources就可以

Environment加載屬性

入口函數(shù)

springApplication.run(args) --> prepareEnvironment

prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {// Create and configure the environmentConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);listeners.environmentPrepared(bootstrapContext, environment);DefaultPropertiesPropertySource.moveToEnd(environment);configureAdditionalProfiles(environment);bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment; }

在prepareEnvironment中,共進行了一下的進步操作:

  • 創(chuàng)建Environment對象:getOrCreateEnvironment()
  • 配置屬性:configureEnvironment()
  • 添加configurationProperties屬性:ConfigurationPropertySources.attach(environment)
  • 通過事件發(fā)布器發(fā)布environment事件:listeners.environmentPrepared(bootstrapContext, environment);
  • 將defaultProperties屬性移到最后面,因為是默認(rèn),所有在后面兜底:DefaultPropertiesPropertySource.moveToEnd(environment)
  • 加載profile配置文件屬性:configureAdditionalProfiles(environment)
  • 綁定SpringApplication對象到Environment中:bindToSpringApplication(environment)
  • getOrCreateEnvironment

    private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {return this.environment;}switch (this.webApplicationType) {case SERVLET:return new StandardServletEnvironment();case REACTIVE:return new StandardReactiveWebEnvironment();default:return new StandardEnvironment();} }
    • 通過:webApplicationType判斷當(dāng)前容器環(huán)境,創(chuàng)建不同的Environment對象

    SERVLET環(huán)境舉例

    public class StandardEnvironment extends AbstractEnvironment {/** System environment property source name: {@value}. */public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";/** JVM system properties property source name: {@value}. */public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";@Overrideprotected void customizePropertySources(MutablePropertySources propertySources) {propertySources.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));}@Overridepublic void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);} }

    可以看出在類種定義了方法:customizePropertySources,
    customizePropertySources:

    • 添加:servletContextInitParams屬性集
    • 添加:servletConfigInitParams屬性集
    • 如果jndi環(huán)境,添加jndiProperties屬性集
    • 調(diào)用付類customizePropertySources方法,初始化java及系統(tǒng)屬性參數(shù)

    supper.customizePropertySources()

    public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";@Override 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())); }


    在StandardServletEnvironment類中,并沒有發(fā)現(xiàn)在哪里調(diào)用:customizePropertySources().此時查看類圖,它的的上層父類:StandardEnvironment也沒有調(diào)用,繼續(xù)查看上層父類:AbstractEnvironment,此時發(fā)現(xiàn)在構(gòu)造函數(shù)中調(diào)用了customizePropertySources()

    public AbstractEnvironment() {customizePropertySources(this.propertySources); }

    只是由于java在實例化的時候,會先調(diào)用父類的構(gòu)造函數(shù),所在執(zhí)行了customizePropertySources(),完成相關(guān)屬性的初始化工作

    • 此時environment中的屬性只有四種
      servletConfigInitParams、servletContextInitParams、systemProperties、systemEnvironment

    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); }

    在方法中通過:configurePropertySources方法來添加:

    • 添加默認(rèn)屬性值
    • 添加命令行屬性值

    configurePropertySources

    protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {MutablePropertySources sources = environment.getPropertySources();DefaultPropertiesPropertySource.ifNotEmpty(this.defaultProperties, sources::addLast);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));}} }

    1.通過函數(shù):DefaultPropertiesPropertySource.ifNotEmpty(this.defaultProperties, sources::addLast) 將硬編碼的defaultProperties對象屬性添加在sources中

    public static void main(String[] args) throws InterruptedException {SpringApplication springApplication = new SpringApplication((SpringBootDemoApplication.class));Properties properties = new Properties();properties.setProperty("study1", "value_study1");springApplication.setDefaultProperties(properties);springApplication.run(args); }//springApplication.setDefaultProperties(properties) public void setDefaultProperties(Properties defaultProperties) {this.defaultProperties = new HashMap<>();for (Object key : Collections.list(defaultProperties.propertyNames())) {this.defaultProperties.put((String) key, defaultProperties.get(key));} }

    2.判斷是否需要添加命令行參數(shù)及args是否傳入的信息,構(gòu)建一個SimpleCommandLinePropertySource對象添加到屬性列表中
    new SimpleCommandLinePropertySource(args)

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

    調(diào)用SimpleCommandLineArgsParser解析器,解析傳入的參數(shù)信息

    SimpleCommandLineArgsParser.parse

    class SimpleCommandLineArgsParser {/*** Parse the given {@code String} array based on the rules described {@linkplain* SimpleCommandLineArgsParser above}, returning a fully-populated* {@link CommandLineArgs} object.* @param args command line arguments, typically from a {@code main()} method*/public CommandLineArgs parse(String... args) {CommandLineArgs commandLineArgs = new CommandLineArgs();for (String arg : args) {if (arg.startsWith("--")) {String optionText = arg.substring(2);String optionName;String optionValue = null;int indexOfEqualsSign = optionText.indexOf('=');if (indexOfEqualsSign > -1) {optionName = optionText.substring(0, indexOfEqualsSign);optionValue = optionText.substring(indexOfEqualsSign + 1);}else {optionName = optionText;}if (optionName.isEmpty()) {throw new IllegalArgumentException("Invalid argument syntax: " + arg);}commandLineArgs.addOptionArg(optionName, optionValue);}else {commandLineArgs.addNonOptionArg(arg);}}return commandLineArgs;}}

    可以看出只對-- 開頭的字符串進行解析,根據(jù)鍵值對來獲取key,value,添加到屬性中

    • 此時environment中的屬性值
      servletConfigInitParams、servletContextInitParams、systemProperties、systemEnvironment、commandLineArgs、defaultProperties

    ConfigurationPropertySources.attach

    public static void attach(Environment environment) {Assert.isInstanceOf(ConfigurableEnvironment.class, environment);MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();PropertySource<?> attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME);if (attached != null && attached.getSource() != sources) {sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);attached = null;}if (attached == null) {sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,new SpringConfigurationPropertySources(sources)));} }

    主要設(shè)置configurationProperties屬性值

    • 此時environment屬性值
      servletConfigInitParams、servletContextInitParams、systemProperties、systemEnvironment、commandLineArgs、defaultProperties、 configurationProperties

    listeners.environmentPrepared

    DefaultPropertiesPropertySource.moveToEnd

    public static final String NAME = "defaultProperties";public static void moveToEnd(MutablePropertySources propertySources) {PropertySource<?> propertySource = propertySources.remove(NAME);if (propertySource != null) {propertySources.addLast(propertySource);} }

    先將defaultProperties刪除,然后在添加,目的是將defaultProperties存到最后一個節(jié)點,用作兜底操作

    configureAdditionalProfiles

    private void configureAdditionalProfiles(ConfigurableEnvironment environment) {if (!CollectionUtils.isEmpty(this.additionalProfiles)) {Set<String> profiles = new LinkedHashSet<>(Arrays.asList(environment.getActiveProfiles()));if (!profiles.containsAll(this.additionalProfiles)) {profiles.addAll(this.additionalProfiles);environment.setActiveProfiles(StringUtils.toStringArray(profiles));}} }

    獲取當(dāng)前需要加載的配置文件后綴

    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);} }

    將spring.main屬性值賦值給:SpringApplication中對應(yīng)的屬性

    ConfigurationClassParser

    • 添加@PropertySources屬性集,在run的refresh中調(diào)用

    org.springframework.context.annotation.ConfigurationClassParser#processPropertySource

    private void processPropertySource(AnnotationAttributes propertySource) throws IOException {String name = propertySource.getString("name");if (!StringUtils.hasLength(name)) {name = null;}String encoding = propertySource.getString("encoding");if (!StringUtils.hasLength(encoding)) {encoding = null;}String[] locations = propertySource.getStringArray("value");Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));for (String location : locations) {try {String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);Resource resource = this.resourceLoader.getResource(resolvedLocation);addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));}catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) {// Placeholders not resolvable or resource not found when trying to open itif (ignoreResourceNotFound) {if (logger.isInfoEnabled()) {logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());}}else {throw ex;}}} }private void addPropertySource(PropertySource<?> propertySource) {String name = propertySource.getName();MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();if (this.propertySourceNames.contains(name)) {// We've already added a version, we need to extend itPropertySource<?> existing = propertySources.get(name);if (existing != null) {PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?((ResourcePropertySource) propertySource).withResourceName() : propertySource);if (existing instanceof CompositePropertySource) {((CompositePropertySource) existing).addFirstPropertySource(newSource);}else {if (existing instanceof ResourcePropertySource) {existing = ((ResourcePropertySource) existing).withResourceName();}CompositePropertySource composite = new CompositePropertySource(name);composite.addPropertySource(newSource);composite.addPropertySource(existing);propertySources.replace(name, composite);}return;}}if (this.propertySourceNames.isEmpty()) {propertySources.addLast(propertySource);}else {String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);propertySources.addBefore(firstProcessed, propertySource);}this.propertySourceNames.add(name); }

    總結(jié)

    以上是生活随笔為你收集整理的SpringBoot基础-Environment解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。