原因:java.lang.IllegalArgumentException:无法解析占位符

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder

我在从 application.properties 文件中读取值时遇到问题并收到以下错误,

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.7.RELEASE:run (default-cli) on project wedding-card: An exception occurred while running. null: InvocationTargetException: Error creating bean with name 'weddingCardConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'aws.s3.access.key' in value "${aws.s3.access.key}" -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.7.RELEASE:run (default-cli) on project wedding-card: An exception occurred while running. null
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)


Caused by: org.apache.maven.plugin.MojoExecutionException: An exception occurred while running. null
    at org.springframework.boot.maven.AbstractRunMojo$IsolatedThreadGroup.rethrowUncaughtException (AbstractRunMojo.java:512)
    at org.springframework.boot.maven.RunMojo.runWithMavenJvm (RunMojo.java:94)
    at org.springframework.boot.maven.AbstractRunMojo.run (AbstractRunMojo.java:244)


Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:498)
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run (AbstractRunMojo.java:543)
    at java.lang.Thread.run (Thread.java:748)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'weddingCardConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'aws.s3.access.key' in value "${aws.s3.access.key}"
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties (AutowiredAnnotationBeanPostProcessor.java:380)

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'aws.s3.access.key' in value "${aws.s3.access.key}"

提供pom.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wedcard</groupId>
    <artifactId>wedding-card</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>wedding-card</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.16</version>
        </dependency>

        <dependency>
            <groupId>com.stripe</groupId>
            <artifactId>stripe-java</artifactId>
            <version>10.0.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk</artifactId>
            <version>1.11.163</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.jhonnymertz</groupId>
            <artifactId>java-wkhtmltopdf-wrapper</artifactId>
            <version>1.1.11-RELEASE</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
<!--        <resources>-->
<!--            <resource>-->
<!--                <directory>resources</directory>-->
<!--                <targetPath>${project.build.outputDirectory}</targetPath>-->
<!--                <includes>-->
<!--                    <include>application.properties</include>-->
<!--                </includes>-->
<!--            </resource>-->
<!--        </resources>-->
    </build>

    <repositories>
        <repository>
            <id>spring.io</id>
            <url>https://repo.spring.io/plugins-release/</url>
        </repository>
    </repositories>

</project>

配置源文件在这里:

@Configuration
@EnableSwagger2
@EnableScheduling
//@PropertySource(value = "classpath:application.properties")
public class WeddingCardConfiguration implements WebMvcConfigurer {
//    @Value("${spring.mail.host}")
//    private String smtpMailHost;
//    @Value("${spring.mail.port}")
//    private int smtpMailPort;
//    @Value("${spring.mail.username}")
//    private String mailUsername;
//    @Value("${spring.mail.password}")
//    private String mailPassword;

    @Value("${aws.s3.access.key}")
    private String awsS3AccessKey;
    @Value("${aws.s3.access.secret}")
    private String awsS3AccessSecret;
    @Value("${aws.s3.bucket.region.name}")
    private String awsBucketRegionName;


    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build();
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*");
    }

//    @Bean
//    public JavaMailSender javaMailSender() {
//        JavaMailSenderImpl sender = new JavaMailSenderImpl();
//        Properties prop = new Properties();
//        prop.put("mail.smtp.auth", "true");
//        prop.put("mail.smtp.starttls.enable", "true"); //TLS
//        sender.setJavaMailProperties(prop);
//        sender.setHost(smtpMailHost);
//        sender.setPort(smtpMailPort);
//        sender.setUsername(mailUsername);
//        sender.setPassword(mailPassword);
//
//        return sender;
//    }

    @Bean
    public AmazonS3 awsS3Client() {
        AWSCredentials credentials = new BasicAWSCredentials(awsS3AccessKey, awsS3AccessSecret);

        return AmazonS3ClientBuilder
                .standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withRegion(awsBucketRegionName)
                .build();
    }
}

该项目提供了标准文件结构:

我已尝试向配置提供 属性 源信息 class 但仍然出现相同的错误:

@Configuration
@EnableSwagger2
@EnableScheduling
@PropertySource(value = "classpath:application.properties")
public class WeddingCardConfiguration implements WebMvcConfigurer {


}

我也尝试过向 pom 文件显式提供资源信息:

     <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>resources</directory>
                <targetPath>${project.build.outputDirectory}</targetPath>
                <includes>
                    <include>application.properties</include>
                </includes>
            </resource>
        </resources>
    </build>

我不断收到同样的错误。这里有什么问题以及如何解决?

ps: 电子邮件配置值是有意注释的,错误与此无关

检查这些属性是否确实在 application.properties 中定义。还有一个 application-aws.properties 文件,如果属性仅在该文件中,那么您需要告诉 Spring Boot 使用 SPRING_PROFILES_ACTIVE=aws 启用 aws 配置文件,或者添加aws 个属性在 application.properties 中具有空值。

如果没有 Spring 引导配置文件被激活,它将只使用 application.properties 中定义的属性。

如果启用 aws 配置文件,它将使用 application.properties 中的属性作为默认值,然后 application-aws.properties 中定义的任何匹配属性将覆盖 application.properties 中的属性] 如果已定义。

如果您尝试执行的操作仅在部署到 AWS 时使用这些 AWS 属性,那么您可能需要创建一个配置对象来保存这些属性(这比使用 @Value 在代码中),并使 AmazonS3 bean 的创建以设置这些属性为条件。

鉴于您的项目结构是标准的 Maven 结构,应该应用配置约定,并且不需要尝试显式包含 application.properties 和额外的 class 路径配置。即 /src/main/resources 下的所有内容都应该在 class 路径上可用,并且在运行时对应用程序可用。

我需要在配置文件中添加一个 bean 来读取额外的属性文件,

    @Bean
    public PropertyPlaceholderConfigurer properties() {
        final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
//        ppc.setIgnoreUnresolvablePlaceholders(true);
        ppc.setIgnoreResourceNotFound(true);

        final List<Resource> resourceLst = new ArrayList<Resource>();

        resourceLst.add(new ClassPathResource("application.properties"));
        resourceLst.add(new ClassPathResource("application-local.properties"));

        ppc.setLocations(resourceLst.toArray(new Resource[]{}));
        return ppc;
    }

之后,它工作正常。