【问题标题】:PropertyPlaceholderConfigurer not loading programmaticallyPropertyPlaceholderConfigurer 未以编程方式加载
【发布时间】:2013-02-25 20:01:26
【问题描述】:

我有一个自定义 ApplicationContext 类,我正在尝试以编程方式加载 PropertyPlaceholderConfigurer,然后在我的 XML 配置文件中使用占位符。

到目前为止,我已经尝试了三种不同的方法,但每次都收到这样的错误:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named '${domain}.testId' is defined

我做错了什么?

上下文类

public class MyApplicationContext extends GenericApplicationContext {
    public MyApplicationContext (String... locations) throws IOException {

        // method one
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this);
        scanner.scan("com.my.package");

        // method two
        new MyPropertyPlaceholderConfigurer().postProcessBeanFactory(getBeanFactory());

        // method three
        getBeanFactory().registerSingleton("propertyPlaceholderConfigurer", new MyPropertyPlaceholderConfigurer());

        // load XML config files
        XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(this);
        for (String location : locations) {
            xmlReader.loadBeanDefinitions(location);
        }
    }
}

XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="test.testId" class="java.lang.String">
        <constructor-arg value="this is the test value" />
    </bean>

    <bean id="prod.testId" class="java.lang.String">
        <constructor-arg value="this is the prod value" />
    </bean>

    <alias name="${domain}.testId" alias="testId" />

</beans>

用法

MyApplicationContext context = new MyApplicationContext(
    new String[] { "test.xml" });
Assert.assertEquals("this is the test value", context.getBean("testId"));

【问题讨论】:

  • 为什么你需要一个自定义上下文来包含 PropertyPlaceholderConfigurer 甚至你自己的自定义上下文?
  • 我的上下文类也进行包扫描和日志初始化。我只是没有在我的示例代码中包含那些额外的东西。我对 Spring 很陌生,但它似乎是一个包含所有这些东西的合理地方。我错了吗?

标签: spring spring-3


【解决方案1】:

我很欣赏有关如何定义 bean 的答案,但事实证明问题要简单得多。我加载 bean 很好,但是在加载所有 bean 后我没有正确初始化我的上下文。一个简单的 refresh() 调用就可以解决问题。

MyApplicationContext context = new MyApplicationContext(
    new String[] { "test.xml" });

context.refresh();   // this runs BeanFactoryPostProcessors like 
                     // MyPropertyPlaceholderConfigurer, among other things

Assert.assertEquals("this is the test value", context.getBean("testId"));

【讨论】:

    【解决方案2】:

    如果您只想使用自己的自定义MyPropertyPlaceholderConfigurer(假设它扩展了PropertyPlaceholderConfigurer,那么您只需将其作为bean 放入您的应用程序上下文中,剩下的一切就由它完成了给你:

    <bean class="my.pkg.MyPropertyPlaceholderConfigurer" />
    

    【讨论】:

    • 那么这需要配置文件吗?不能用代码实现吗?
    • 你已经有了一个配置 XML (test.xml),这就是它应该去的地方。
    • 为什么使用配置 XML 比将 bean 作为组件扫描更好或不同?我的系统比我的问题中显示的三个文件要复杂一些,我希望有一个比将它添加到我的主要 XML 或创建第二个文件更好的解决方案。
    • 在我看来,创建自己的应用程序上下文并不是一个好主意,因为有不同类型的上下文(例如 XmlWebApplicationContextClassPathXmlApplicationContext),因此您必须将它们全部子类化.
    • 这很合理,尽管对于我的应用程序,我可以选择一个基类并坚持使用它(在我的例子中是 GenericApplicationContext)。我不是在建图书馆。但很高兴知道首选方法不是子类。我会考虑尽快解决这个问题。
    【解决方案3】:

    这是使您的属性在配置文件中可访问的标准方式。

    <util:list id="locations">
        <value>classpath:appconfig.properties</value>
        <value>classpath:jdbc.properties</value>
    </util:list>
    
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
          p:ignoreResourceNotFound="true"
          p:locations-ref="locations" />
    
    <!-- bean that uses properties -->
    <bean id="dataSource"
          class="com.mchange.v2.c3p0.ComboPooledDataSource"
          p:driverClass="${jdbc.driver}"
          p:jdbcUrl="${jdbc.url}"
          p:user="${jdbc.user}"
          p:password="${jdbc.pw}"
          p:initialPoolSize="5"
          p:minPoolSize="5"
          p:maxPoolSize="50"
          p:idleConnectionTestPeriod="5" />
    

    如何在任何地方的配置文件中“注入”属性的另一种非常有用的方法是使用 maven:您使用相同的语法 ${property-name} 但在 maven 构建过程中较早地提供了值 - 这是 maven 配置的相关部分:

    <properties>
    <jdbc.url>jdbc:mysql://localhost:3306/dummyuserdb</jdbc.url>
    <jdbc.user>root</jdbc.user>
    <jdbc.pw>admin</jdbc.pw>
    </properties> 
    

    你必须在 Maven 过滤资源中包含你的 spring 的配置目录:

    <build>
        <resources>
        <resource>
            <directory>${basedir}/src/main/webapp/WEB-INF/spring-config</directory>
            <filtering>true</filtering>
            </resource>
    </resources>
    

    或者如果您更喜欢 java 配置:

     @Configuration
     @PropertySource(value = "config/jdbc.properties")
     public class BaseWebConfig {
    
        @Autowired Environment env;
    
        @Bean
        public MyBean myBean() {
           MyBean myBean = new MyBean();
           String propertyValue = env.getProperty("my-property-name");
           // do something with myBean and propertyValue
           return myBean;
        }
     }
    

    }

    【讨论】:

      猜你喜欢
      • 2014-12-02
      • 1970-01-01
      • 2018-01-15
      • 1970-01-01
      • 1970-01-01
      • 2011-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多