【问题标题】:Spring FrameworkServlet won't load Properties during Tomcat startupSpring FrameworkServlet 在 Tomcat 启动期间不会加载属性
【发布时间】:2017-09-10 17:11:52
【问题描述】:

Spring PropertyPlaceholderConfigurer 有一个奇怪的问题

所有的 JUnit 测试都通过了,但是当我启动 Tomcat 时,我遇到了属性初始化问题:

// First root initialization, the properties are fine
[...]
INFO: Initializing Spring root WebApplicationContext
14:21:13.195 INFO  [QuartzProperties] - QuartzProperties: false 0 0/30 * * * ? true 18:00 1

// Second 'servlet' initialization, the properties are empty
[...]
INFO: Initializing Spring FrameworkServlet 'global'
14:21:16.133 INFO  [QuartzProperties] - QuartzProperties: false  false ${quartz.triggertime} 0

servlet 上下文初始化不使用属性,并触发 Quartz 库崩溃(无效值)。

我看不出配置有什么问题,也不太明白发生了什么:

web.xlm

[...]
<servlet>
    <servlet-name>global</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>global</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:/applicationContext.xml
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

applicationContext.xml

<bean id="allProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
    <property name="ignoreResourceNotFound" value="false" />
    <property name="locations">
        <list>
            <value>file:///${WEBSITE_HOME}/conf/jdbc.properties</value>
            <value>file:///${WEBSITE_HOME}/conf/hibernate.properties</value>
            <value>file:///${WEBSITE_HOME}/conf/quartz.properties</value>
        </list>
    </property>
</bean>

WEBSITE_HOME 值来自操作系统环境。

有人知道为什么全局 servlet 初始化中的属性为空吗?

【问题讨论】:

  • 您的实际问题是为什么您的 bean(以及您的整个应用程序)加载了两次! (你的石英材料不应该运行两次!)。此外,PropertyPlaceholderConfigurer 仅适用于它定义的上下文(ContextLoaderLIstenert),它不适用于依赖上下文(DispatcherServlet)。它是一个BeanFactoryPostProcessor,并且(幸运的是)只在它定义的相同上下文中运行。
  • 感谢您的评论。我读过双 Spring init 很常见。看看这个答案:stackoverflow.com/a/20753902/5444618 - 你怎么看?
  • 不,它不是...这意味着您正在加载您的应用程序两次,您不应该这样做,因为这最终会导致奇怪的调试问题、事务问题、数据库问题、内存问题。是的,您有 2 个上下文,但这些上下文应该包含不同的 bean 而不是相同的......
  • 它们是两种不同的豆子。但是 servlet 上下文 bean 不加载属性,只有根 bean 加载,这让我感到困惑。如果确定只创建一个 bean 会更容易......
  • 正如我在其他评论中所说,PropertyPlaceholderConfigurer 在加载它的同一上下文中运行。要让它在 servlet 上下文中工作,您必须再次定义它。但是为什么你需要两个调度器,你应该需要 1 个......

标签: java spring spring-mvc tomcat8


【解决方案1】:

您还需要在 servlet 定义中包含 init 参数。

<init-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>classpath:/applicationContext.xml</param-value>
</init-param>

[...]
<servlet>
    <servlet-name>global</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:/applicationContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>global</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:/applicationContext.xml
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

【讨论】:

  • 谢谢,现在我只需要找到一种方法从根上下文中删除 bean,就像 @M.Deinum 在 cmets 中建议的那样,我会很好的。
  • 好吧,那就太好了:)
猜你喜欢
  • 2017-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-13
相关资源
最近更新 更多