springBoot

关于yml文件无法自动提示

img


在复习springBoot项目,发现yml文件无法自动提示,本想设置一下,可是发现这个问题,这个ok这里怎么点不了,有木有大佬教一下。

在springBoot项目中,想要yml文件自动提示的话,你可以在pom.xml文件中加一个依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
 </dependency>

你尝试一下,看看可以不,望采纳!!!

  • 建议你看下这篇博客👉 :yml修改端口无效(SpringBoot中)
  • 除此之外, 这篇博客: Springboot加载yml配置文件源码梳理中的 Springboot 启动过程是一个复杂的流程,现在将yml加载拆分出来单独研究一下 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • ApplicationArguments 提供对用于运行的参数的访问
    ConfigurableEnvironment 的propertySources 存放yml的配置参数
    getSearchLocations 获取默认文件放置路径 classpath:/,classpath:/config/,file:./,file:./config/

    public ConfigurableApplicationContext run(String... args) {
    		StopWatch stopWatch = new StopWatch();
    		stopWatch.start();
    		ConfigurableApplicationContext context = null;
    		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    		configureHeadlessProperty();
    		SpringApplicationRunListeners listeners = getRunListeners(args);
    		listeners.starting();
    		try {
    			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
    					args);
    			ConfigurableEnvironment environment = prepareEnvironment(listeners,
    					applicationArguments);
    			configureIgnoreBeanInfo(environment);
    			*********其它跟本业务无关的先注掉***********************
    		}
    		*********其它跟本业务无关的先注掉***********************
    		return context;
    	}
    

    getOrCreateEnvironment 返回一个标准的servlet环境类

    private ConfigurableEnvironment prepareEnvironment(
    			SpringApplicationRunListeners listeners,
    			ApplicationArguments applicationArguments) {
    		// Create and configure the environment
    		ConfigurableEnvironment environment = getOrCreateEnvironment();
    		configureEnvironment(environment, applicationArguments.getSourceArgs());
    		listeners.environmentPrepared(environment);
    		bindToSpringApplication(environment);
    		if (this.webApplicationType == WebApplicationType.NONE) {
    			environment = new EnvironmentConverter(getClassLoader())
    					.convertToStandardEnvironmentIfNecessary(environment);
    		}
    		ConfigurationPropertySources.attach(environment);
    		return environment;
    	}
    

    EventPublishingRunListener实现了SpringApplicationRunListener接口
    environmentPrepared配置environment

    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));
    		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    			Executor executor = getTaskExecutor();
    			if (executor != null) {
    				executor.execute(() -> invokeListener(listener, event));
    			}
    			else {
    			//执行这一行
    				invokeListener(listener, event);
    			}
    		}
    	}
    	************************一直往下跟
    
    	
    

    loadPostProcessors加载4个进程类
    1、SystemEnvironmentPropertySourceEnvironmentPostProcessor
    2、SpringApplicationJsonEnvironmentPostProcessor
    3、CloudFoundryVcapEnvironmentPostProcessor
    4、ConfigFileApplicationListener 加载配置文件

    private void onApplicationEnvironmentPreparedEvent(
    			ApplicationEnvironmentPreparedEvent event) {
    		List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
    		postProcessors.add(this);
    		AnnotationAwareOrderComparator.sort(postProcessors);
    		for (EnvironmentPostProcessor postProcessor : postProcessors) {
    			postProcessor.postProcessEnvironment(event.getEnvironment(),
    					event.getSpringApplication());
    		}
    	}
    

    进入ConfigFileApplicationListener 的addPropertySources 方法加载文件,实例化environment

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

    内部类 Loader 和load方法

    public void load() {
    			this.profiles = Collections.asLifoQueue(new LinkedList<Profile>());
    			this.processedProfiles = new LinkedList<>();
    			this.activatedProfiles = false;
    			this.loaded = new LinkedHashMap<>();
    			initializeProfiles();
    			while (!this.profiles.isEmpty()) {
    				Profile profile = this.profiles.poll();
    				//如果profiles文件不为空,那么加载文件
    				load(profile, this::getPositiveProfileFilter,
    						addToLoaded(MutablePropertySources::addLast, false));
    				this.processedProfiles.add(profile);
    			}
    			load(null, this::getNegativeProfileFilter,
    					addToLoaded(MutablePropertySources::addFirst, true));
    			addLoadedPropertySources();
    		}
    

    getSearchLocations 获取默认文件放置路径 classpath:/,classpath:/config/,file:./,file:./config/
    然后遍历加载路径下的文件名 application 后缀为properties,XML,yml,yaml

    private void load(Profile profile, DocumentFilterFactory filterFactory,
    				DocumentConsumer consumer) {
    			getSearchLocations().forEach((location) -> {
    				boolean isFolder = location.endsWith("/");
    				Set<String> names = (isFolder ? getSearchNames() : NO_SEARCH_NAMES);
    				names.forEach(
    						(name) -> load(location, name, profile, filterFactory, consumer));
    			});
    		}
    

    最终遍历到你的yml存放的目录,然后执行加载

    private void load(PropertySourceLoader loader, String location, Profile profile,
    				DocumentFilter filter, DocumentConsumer consumer) {
    			try {
    				Resource resource = this.resourceLoader.getResource(location);
    				String description = getDescription(location, resource);
    				if (profile != null) {
    					description = description + " for profile " + profile;
    				}
    				if (resource == null || !resource.exists()) {
    					this.logger.trace("Skipped missing config " + description);
    					return;
    				}
    				if (!StringUtils.hasText(
    						StringUtils.getFilenameExtension(resource.getFilename()))) {
    					this.logger.trace("Skipped empty config extension " + description);
    					return;
    				}
    				String name = "applicationConfig: [" + location + "]";
    				List<Document> documents = loadDocuments(loader, name, resource);
    				if (CollectionUtils.isEmpty(documents)) {
    					this.logger.trace("Skipped unloaded config " + description);
    					return;
    				}
    				List<Document> loaded = new ArrayList<>();
    				for (Document document : documents) {
    					if (filter.match(document)) {
    						maybeActivateProfiles(document.getActiveProfiles());
    						addProfiles(document.getIncludeProfiles());
    						loaded.add(document);
    					}
    				}
    				Collections.reverse(loaded);
    				if (!loaded.isEmpty()) {
    					loaded.forEach((document) -> consumer.accept(profile, document));
    					this.logger.debug("Loaded config file " + description);
    				}
    			}
    			catch (Exception ex) {
    				throw new IllegalStateException("Failed to load property "
    						+ "source from location '" + location + "'", ex);
    			}
    		}
    
    

    loadDocuments(loader, name, resource)

    private List<Document> loadDocuments(PropertySourceLoader loader, String name,
    				Resource resource) throws IOException {
    				//获取resource 对应的缓存key
    			DocumentsCacheKey cacheKey = new DocumentsCacheKey(loader, resource);
    			List<Document> documents = this.loadDocumentsCache.get(cacheKey);
    			if (documents == null) {
    			//缓存中没有才执行load 方法加载
    				List<PropertySource<?>> loaded = loader.load(name, resource);
    				documents = asDocuments(loaded);
    				this.loadDocumentsCache.put(cacheKey, documents);
    			}
    			return documents;
    		}
    

    OriginTrackedYamlLoader yaml文件加载器

    public List<Map<String, Object>> load() {
    		final List<Map<String, Object>> result = new ArrayList<>();
    		//回调函数 result.add(getFlattenedMap(map)
    		process((properties, map) -> result.add(getFlattenedMap(map)));
    		//返回最后加载的数据
    		return result;
    	}
    
    protected void process(MatchCallback callback) {
    		Yaml yaml = createYaml();
    		for (Resource resource : this.resources) {
    		//最后加载文件的方法 process(callback, yaml, resource)
    			boolean found = process(callback, yaml, resource);
    			if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
    				return;
    			}
    		}
    	}
    

    这里是引用

    private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
    		int count = 0;
    		try {
    			if (logger.isDebugEnabled()) {
    				logger.debug("Loading from YAML: " + resource);
    			}
    			Reader reader = new UnicodeReader(resource.getInputStream());
    			try {
    				for (Object object : yaml.loadAll(reader)) {
    				//将加载的yml文件内容转换成map,然后执行callback 方法将map里的内容放入result 中
    					if (object != null && process(asMap(object), callback)) {
    						count++;
    						if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND) {
    							break;
    						}
    					}
    				}
    				//省略****
    			}
    			finally {
    				reader.close();
    			}
    		}
    		catch (IOException ex) {
    			handleProcessError(resource, ex);
    		}
    		return (count > 0);
    	}
    

    URLClassLoader以流的形式加载文件返回 BufferedInputStream,然后包装成Reader

    public InputStream getResourceAsStream(String name) {
            URL url = getResource(name);
            try {
                if (url == null) {
                    return null;
                }
                URLConnection urlc = url.openConnection();
                InputStream is = urlc.getInputStream();
                if (urlc instanceof JarURLConnection) {
                    JarURLConnection juc = (JarURLConnection)urlc;
                    JarFile jar = juc.getJarFile();
                    synchronized (closeables) {
                        if (!closeables.containsKey(jar)) {
                            closeables.put(jar, null);
                        }
                    }
                } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
                    synchronized (closeables) {
                        closeables.put(is, null);
                    }
                }
                return is;
            } catch (IOException e) {
                return null;
            }
        }