Tomcat无法读取Spring-Boot应用程序属性

28

我对Spring/Java相对较新,在工作中正在研究使用Spring Boot进行项目开发。我一直在跟随指南学习,最终成功搭建了一个(半工作)的Web应用程序MVC+JPA用于数据访问。当我通过Jar方法部署应用程序时,一切都正常运行:

java -jar build/libs/client.jar

然而,我们的应用最终将部署到Tomcat(v7.0.40),因此我需要从项目创建war文件。我遵循了spring.io网站上将jar转换为war指南,并遇到了一个问题。似乎它没有加载application.properties文件。以下是关键代码段:

src/main/java/hello/GreetingController:

@Controller
@Configuration
public class GreetingController {
    @Value("${app.username}")
    private String username;

    @RequestMapping("/greeting")
    public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
        model.addAttribute("name", name);
        model.addAttribute("username", username);
        return "greeting";
    }
} 

src/main/java/hello/Application.java

@ComponentScan
@EnableAutoConfiguration
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

src/main/java/hello/HelloWebXml.java

public class HelloWebXml extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
}

src/main/resources/application.properties

app.username=foo

为了完整起见,这是 build.gradle 文件:

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-snapshot" }
        mavenLocal()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:0.5.0.M6")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'war'

war {
    baseName = 'client'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
    maven { url "http://repo.spring.io/libs-snapshot" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:0.5.0.M6")
    compile("org.thymeleaf:thymeleaf-spring3:2.0.16")
    testCompile("junit:junit:4.11")
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.8'
}

我构建这个应用程序:

gradle clean build

将Tomcat中的war文件删除,然后输出日志并查看以下内容:

SEVERE: ContainerBase.addChild: start:
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina]
.StandardHost[localhost].StandardContext[/client]]
...
...
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating the bean
with name 'greetingController': Injection of autowired dependencies failed; nested exception
is java.lang.IllegalArgumentException: Could not resolve placeholder 'app.username' in string
value "${app.username}"
...
...
...

就像我说的,当我通过一个jar包运行它时它能够工作,但是当我部署到Tomcat上时就无法工作。我还查看了$TOMCAT_HOME/webapps/client/WEB-INF/classes目录中的application.properties文件,因此我认为它应该在类路径上。我的问题是,为什么Tomcat没有加载它?我已经尝试搜索各种资源,但似乎没有其他人遇到这个问题,所以我不确定是我配置有误还是别的什么原因。

提前感谢您的帮助。


Spring Boot 应该默认加载 application.properties。尝试在你的 @Configuration 类上添加 @PropertySource("application.properties"),看它是否能够找到它。 - Sotirios Delimanolis
再次感谢,我已经添加了它,但是注意到编译器警告:Cannot find annotation method 'value()' in type 'Repeatable': class file for java.lang.annotation.Repeatable not found.当我将它放入tomcat时,我得到了以下错误: Failed to load bean class: hello.Application; nested exception is org.springframework.core.NestedIOException: Unable to collect imports; nested exception is java.lang.ClassNotFoundException: java.lang.annotation.Repeatable - loganasherjones
你应该发布它。完整的内容应该是 @PropertySource("classpath:application.properties") - Sotirios Delimanolis
抱歉,我在还没编辑完之前就误按了回车键。 - loganasherjones
3
@PropertySource 注解可以与 Spring Boot 应用程序一起使用,但如果它是 classpath:application.properties,则不需要声明它(并且某些框架功能无法使用 @PropertySource 进行配置)- 尽管这在此处不相关。 - Dave Syer
显示剩余8条评论
4个回答

25

2
除了上面的一些评论,这最终对我起作用了。我的问题仍然是,为什么一开始它没有加载属性呢?此外,将其添加到我的控制器文件中会给我带来一个编译器警告,我还没有完全弄清楚。 - loganasherjones
5
重复我上面的评论:在Spring Boot应用程序中这是不必要的。 - Dave Syer
这导致了一个相当奇怪的错误: 在使用Java 7上的Spring Boot时,出现了“ClassCastException:PropertySource无法转换为java.util.Map”。 - Mike Adler
2
@MikeAdler 这个答案是指 PropertySources,它是复数形式,而不是单数形式的 PropertySource - HairOfTheDog
谢谢!这个没问题,但是你知道怎么从其他模块加载 application-xxx.properties 文件吗? - Cataclysm

12

问题是您尝试在@Configuration类中使用@Value注释。根据@PropertySource的JavaDoc:

 

为了使用来自PropertySource的属性解析<bean>定义或@Value注释中的${...}占位符,必须注册一个PropertySourcesPlaceholderConfigurer。在XML中使用<context:property-placeholder>时会自动发生,但是在使用@Configuration类时,必须使用静态@Bean方法显式注册。

例如,将以下行添加到@Configuration类中:

@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}
然而,在您的示例中,更合适的方法是将@Configuration注解从GreetingController类(它不包含任何配置)移动到Application类。由于Application类不包含任何@Value注解,因此应该可以工作,无需建议添加静态PropertySourcesPlaceholderConfigurer bean。

0

我认为那些将默认命名“application.[properties,yaml,等]”更改为“service.[properties,yaml,等]”的人,可以将此添加到build.gradle任务中:

bootRun {
    systemProperties = [
       'spring.config.name':'service'
    ]
}

0
我来到这里寻找同样的问题。当Spring Boot应用程序作为war在Tomcat内运行时,application.properties文件无法加载,但在使用嵌入式Tomcat运行时却可以正常工作。问题最终是文件名引起的。我使用了Application.properties而不是application.properties。在从Tomcat运行时,似乎区分大小写。我把它放在这里,以便如果有人犯了和我一样愚蠢的错误。
2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'file:./config/application.xml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'file:./config/application.yml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'file:./config/application.properties',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'file:./config/application.yaml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'file:./application.xml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'file:./application.yml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'file:./application.properties',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'file:./application.yaml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'classpath:/config/application.xml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'classpath:/config/application.yml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'classpath:/config/application.properties',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'classpath:/config/application.yaml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'classpath:/application.xml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'classpath:/application.yml',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'classpath:/application.properties',未找到资源 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件 'classpath:/application.yaml',未找到资源

我遇到了同样的问题。但是文件Application.properties在maven构建期间会默认生成。感谢@janardhan,我卡了好几个小时。 - OopsDev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接