Spring boot项目启动报错 java.lang.NoSuchMethodError: org.yaml.snakeyaml.nodes.ScalarNode.getScalarStyle()L

具体报错内容如下:

java.lang.NoSuchMethodError: org.yaml.snakeyaml.nodes.ScalarNode.getScalarStyle()Lorg/yaml/snakeyaml/DumperOptions$ScalarStyle;
	at org.springframework.boot.env.OriginTrackedYamlLoader$KeyScalarNode.(OriginTrackedYamlLoader.java:127)
	at org.springframework.boot.env.OriginTrackedYamlLoader$KeyScalarNode.get(OriginTrackedYamlLoader.java:138)
	at org.springframework.boot.env.OriginTrackedYamlLoader$KeyScalarNode.get(OriginTrackedYamlLoader.java:133)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
	at org.springframework.boot.env.OriginTrackedYamlLoader$OriginTrackingConstructor.replaceMappingNodeKeys(OriginTrackedYamlLoader.java:99)
	at org.springframework.boot.env.OriginTrackedYamlLoader$OriginTrackingConstructor.constructObject(OriginTrackedYamlLoader.java:92)
	at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:161)
	at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:127)
	at org.yaml.snakeyaml.Yaml$1.next(Yaml.java:547)
	at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:161)
	at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:134)
	at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:75)
	at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadDocuments(ConfigFileApplicationListener.java:572)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:526)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadForFileExtension(ConfigFileApplicationListener.java:500)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:467)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.lambda$null$6(ConfigFileApplicationListener.java:448)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.lambda$load$7(ConfigFileApplicationListener.java:447)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:444)
	at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:332)
	at org.springframework.boot.context.config.ConfigFileApplicationListener.addPropertySources(ConfigFileApplicationListener.java:207)
	at org.springframework.boot.context.config.ConfigFileApplicationListener.postProcessEnvironment(ConfigFileApplicationListener.java:190)
	at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent(ConfigFileApplicationListener.java:177)
	at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent(ConfigFileApplicationListener.java:163)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
	at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:75)
	at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54)
	at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:347)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:306)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
	at com.mmr.BasicKnowledgeApplication.main(BasicKnowledgeApplication.java:14)

参考文章:https://blog.csdn.net/liaokailin/article/details/48878447  Spring boot 资源文件加载时序图

不难发现,问题出在加载properties文件的阶段,这里我们找到org.springframework.boot.env.PropertySourceLoader 配置文件加载器。

package org.springframework.boot.env;

import java.io.IOException;
import java.util.List;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;

public interface PropertySourceLoader {
    String[] getFileExtensions();

    List> load(String name, Resource resource) throws IOException;
}

此接口的实现类有两个,分别是PropertiesPropertySourceLoader和YamlPropertySourceLoader。 观察getFileExtensions()函数发现,前者用于解析".proerties"或".xml"结尾的配置文件,而后者专注与解析".yml"或".yaml"结尾的配置文件。

因此让我们来看YamlPropertySourceLoader

public class YamlPropertySourceLoader implements PropertySourceLoader {
    public YamlPropertySourceLoader() {
    }

    public String[] getFileExtensions() {
        return new String[]{"yml", "yaml"};
    }

    public List> load(String name, Resource resource) throws IOException {
        if (!ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", (ClassLoader)null)) {
            throw new IllegalStateException("Attempted to load " + name + " but snakeyaml was not found on the classpath");
        } else {
            List> loaded = (new OriginTrackedYamlLoader(resource)).load();
            if (loaded.isEmpty()) {
                return Collections.emptyList();
            } else {
                List> propertySources = new ArrayList(loaded.size());

                for(int i = 0; i < loaded.size(); ++i) {
                    String documentNumber = loaded.size() != 1 ? " (document #" + i + ")" : "";
                    propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber, (Map)loaded.get(i)));
                }

                return propertySources;
            }
        }
    }
}

不难发现一定要有 "org.yaml.snakeyaml.Yaml" 存在,才可以解析,否则返回null。

解决办法很简单,在pom.xml中加上: 


	org.yaml
	snakeyaml
	${snakeyaml.version}

 

但其实,上述做法十分愚蠢,yaml解析器在spring-boot-starter中已经申明过了,一般不太可能需要手动引入。如下图所示:


  org.yaml
  snakeyaml
  1.19
  runtime

我本次出现问题的原因在于 我在子工程的pom.xml中用到了javafaker,


	com.github.javafaker
	javafaker
	0.16

上述代码的致命错误在于没有指明作用范围。默认的作用范围是complie 也即无论在编译还是运行(项目的所有生命周期)都会起作用,再看看javafaker的pom.xml


	org.yaml
	snakeyaml
	1.20
	android

不难发现,这是一个特殊jar包并且依赖于android,按照就近原则,子工程引用的配置将覆盖从父工程继承而来的配置,从而导致错误的发生。

解决办法非常简单,只需要为javafaker加一个作用域为test即可。


	com.github.javafaker
	javafaker
	0.16
	test

 

你可能感兴趣的:(Spring boot项目启动报错 java.lang.NoSuchMethodError: org.yaml.snakeyaml.nodes.ScalarNode.getScalarStyle()L)