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

Posted

技术标签:

【中文标题】Tomcat 不读取 Spring-Boot 应用程序属性【英文标题】:Tomcat Not reading Spring-Boot Application Properties 【发布时间】:2014-01-07 04:37:18 【问题描述】:

我对 spring/java 还很陌生,并且一直在为我工作的项目检查 spring-boot。我一直在遵循指南,终于有了一个(半)工作的网络应用程序 MVC + JPA 用于数据访问。当我通过 Jar 方法部署应用程序时,一切正常:

java -jar build/libs/client.jar

但是,我们的应用程序最终将部署到 Tomcat (v7.0.40),因此我需要从项目中创建一个 war 文件。我遵循了 spring.io 网站上的converting jars to war 指南并遇到了问题。它似乎没有加载 application.properties 文件。以下是重要的代码sn-ps:

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,然后tail out日志看看如下:

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。尝试将 @PropertySource("application.properties") 添加到您的 @Configuration 类中,看看它是否真的找到它。 嘿@SotiriosDelimanolis 感谢您的回复。不幸的是,这也不起作用。当 tomcat 尝试加载战争时,我得到了 FileNotFoundException。如果需要,我可以给你更多细节,请告诉我。 对不起,应该是classpath:application.properties 再次感谢,我继续添加,但注意到编译器警告: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 @SotiriosDelimanolis @PropertySource 注解可以与 Spring Boot 应用程序一起使用,但如果它是 classpath:application.properties 则不需要声明它(并且有一些框架功能不能配置为@PropertySource) - 不过这里不相关。 【参考方案1】:

听从这些人的建议:http://blog.codeleak.pl/2013/11/how-to-propertysource-annotations-in.html

尝试:

@PropertySources(value = @PropertySource("classpath:application.properties"))

然后为胜利而繁荣。

【讨论】:

连同上面的一些 cmets,这最终对我有用。我的问题仍然是,为什么它不首先加载属性?此外,将它添加到我的控制器文件中会给我一个编译器警告,我还没有完全弄清楚。 重复我上面的评论:这在 Spring Boot 应用程序中不是必需的。 这会导致一个相当奇怪的错误:“ClassCastException: PropertySource cannot be cast to java.util.Map” while using Spring Boot on Java 7 @MikeAdler 这个答案指的是PropertySources,它是复数,而不是PropertySource,它是单数 谢谢!这没关系,但你知道如何从其他模块加载application-xxx.properties 文件吗?【参考方案2】:

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

为了使用 PropertySource 中的属性解析 定义或 @Value 注释中的 $... 占位符,必须注册一个 PropertySourcesPlaceholderConfigurer。这在 XML 中使用 时会自动发生,但在使用 @Configuration 类时必须使用静态 @Bean 方法显式注册。

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

@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() 
    return new PropertySourcesPlaceholderConfigurer();


但是,在您的示例中,更合适的方法是将 @Configuration 注释从 GreetingController 类(它不包含任何配置)移动到 Application 类。由于Application 类不包含任何@Value 注释,它应该可以在不建议添加静态PropertySourcesPlaceholderConfigurer bean 的情况下工作。

【讨论】:

【参考方案3】:

我来这里是为了寻找同样的问题。当 Spring Boot 应用程序在 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]]] 跳过配置文件“类路径:/config/application.xml”资源未找到 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件“类路径:/config/application.yml”资源未找到 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件“类路径:/config/application.properties”资源未找到 2015-09-10 14:42:13,982 调试 o.s.b.c.c.ConfigFileApplicationListener [ContainerBackgroundProcessor[StandardEngine[Catalina]]] 跳过配置文件“类路径:/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]]] 跳过配置文件“类路径:/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,我被困了好几个小时【参考方案4】:

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

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

【讨论】:

以上是关于Tomcat 不读取 Spring-Boot 应用程序属性的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat中的spring-boot应用程序战争部署,现有的spring web应用程序失败

在一个 Tomcat 上运行多个 Spring-boot 应用程序

带有tomcat和cxf-servlet的spring-boot

Tomcat需要很长时间才能识别spring-boot应用程序的启动

使用 IntelliJ 部署启用嵌入式 tomcat 的 spring-boot 应用程序

使用war将spring-boot和angular 7应用程序部署到tomcat 8.5中