无法在创建SpringLiquibase bean的静态工厂方法中使用占位符

无法在创建SpringLiquibase bean的静态工厂方法中使用占位符,spring,liquibase,applicationcontext,Spring,Liquibase,Applicationcontext,Spring 3.1.0,Liquibase 2.0.5在Glassfish 2.1.1上运行-我从一位早已离开的同事那里继承了这个applicationContext.xml,它以如下方式构造SpringLiquibase bean: <bean id="liquibaseConfiguratore" factory-method="createLiquibaseBean" class="com.whatever.LiquibaseFactory"> <constru

Spring 3.1.0,Liquibase 2.0.5在Glassfish 2.1.1上运行-我从一位早已离开的同事那里继承了这个applicationContext.xml,它以如下方式构造SpringLiquibase bean:

<bean id="liquibaseConfiguratore" factory-method="createLiquibaseBean" class="com.whatever.LiquibaseFactory">
    <constructor-arg name="dataSource" ref="dataSourceConfiguratore"/>
    <constructor-arg name="changeLog" value="classpath:liquibase/configuratore-db-changelog.xml"/>
    <constructor-arg name="propFileName" value="/opt/whatever/ec_properties.properties"/>
</bean>
现在我需要参数化changeLog值,以便我的bean声明变成:

<bean id="liquibaseConfiguratore" factory-method="createLiquibaseBean" class="com.whatever.LiquibaseFactory"> 
    <constructor-arg name="dataSource" ref="dataSourceConfiguratore"/>
    <constructor-arg name="changeLog" value="${tgo.liquibase.changelog.filename}"/>
    <constructor-arg name="propFileName" value="/opt/whatever/ec_properties.properties"/>
</bean>
读了这篇文章后,我将原始字符串放入属性文件中

tgo.liquibase.changelog.filename=classpath:liquibase/configuratore-db-changelog.xml
并将道具声明为:

<context:property-placeholder location="file:///opt/whatever/custom_properties.properties" />
显然,当XML中有一个普通字符串时,就会找到解析器。在我放置占位符的那一刻,解析器就不存在了。但看起来占位符解析正确,至少在屏幕上是这样

我尝试了一些变化:

  • 将文件:/absolute/path/to/configuratore-db-changelog.xml放入属性中
  • 将classpath*:liquibase/configuratore-db-changelog.xml放入属性中
  • 将属性“index=0,1,2”而不是“name”放在tag constructor.arg中
但问题仍然存在

如何使用占位符指定changeLog参数?

以下是完整的堆栈跟踪:

[#||2014-06-25T09:19:54.860+0200严重sun-appserver2.1 javax.enterprise.system.container.web | ThreadID=12;_ThreadName=pool-1-thread-6;_RequestID=36e46602-c248-4e54-844e-6e5be5bpw8;| WebModule[/FastWebMe]LoaderListener类的侦听器实例发送上下文初始化事件异常
org.springframework.beans.factory.BeanCreationException:创建名为“LiquibaSeconfigurate”的bean时出错,该bean在类路径资源[spring/applicationContext.xml]中定义:调用init方法失败;嵌套异常为liquibase.exception.LiquibaseException:找不到支持类路径的解析器:liquibase/configuratore-db-changelog.xml
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
位于org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
位于org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
位于org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
位于org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
位于org.springframework.beans.factory.support.DefaultListableBeanFactory.PreInstanceSingleton(DefaultListableBeanFactory.java:585)
位于org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
位于org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
位于org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:384)
位于org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
位于org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
位于org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4632)
位于org.apache.catalina.core.StandardContext.start(StandardContext.java:5312)
位于com.sun.enterprise.web.WebModule.start(WebModule.java:353)
位于com.sun.enterprise.web.LifecycleStarter.doRun(LifecycleStarter.java:58)
位于com.sun.appserv.management.util.misc.RunnableBase.runSync(RunnableBase.java:304)
位于com.sun.appserv.management.util.misc.RunnableBase.run(RunnableBase.java:341)
位于java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
位于java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
位于java.util.concurrent.FutureTask.run(FutureTask.java:138)
位于java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
位于java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
运行(Thread.java:619)
原因:liquibase.exception.LiquibaseException:找不到支持类路径的解析器:liquibase/configuratore-db-changelog.xml
位于liquibase.parser.ChangeLogParserFactory.getParser(ChangeLogParserFactory.java:61)
更新(liquibase.java:107)
位于liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:262)
位于liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:245)
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
…还有24个
|#]
这里是LIQUIBASEFACTORY:

package com.whatever.util;

import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

public class LiquibaseFactory {

private static boolean enabled = !StringUtils.equals(
        System.getProperty("liquibase.disable"), "true");

private static Logger log = Logger.getLogger(LiquibaseFactory.class);

public static CustomLiquibase createLiquibaseBean(DataSource dataSource,
        String changeLog, String propFileName) {

    log.info("dataSource is " + dataSource);
    log.info("changeLog is " + changeLog);
    log.info("propFileName is " + propFileName);

    CustomLiquibase customLiquibase = null;
    if (enabled) {

        log.info("creating customLiquibase ENABLED");

        customLiquibase = new CustomLiquibase(propFileName);
        customLiquibase.setDataSource(dataSource);
        customLiquibase.setChangeLog(changeLog);

    } else {

        log.warn("Liquibase has been disabled");

        log.warn("\n\n" + StringUtils.repeat("*", 80));
        log.warn(StringUtils.repeat("*", 80) + "\n\n");

    }
    return customLiquibase;
}

}
这里是CUSTOMLIQUIBASE:

package com.whatever.util;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import liquibase.integration.spring.SpringLiquibase;
import org.apache.log4j.Logger;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

public class CustomLiquibase extends SpringLiquibase {

private static final Logger LOGGER = Logger
        .getLogger(CustomLiquibase.class);

public CustomLiquibase(String propertiesName) {

    super();
    LOGGER.info("propertiesName is " + propertiesName);

    Resource resource = new FileSystemResource(new File(propertiesName));
    try {
        LOGGER.info("resource is " + resource);

        Properties props = PropertiesLoaderUtils.loadProperties(resource);
        Map<String, String> ps = new HashMap<String, String>();
        for (Object key : props.keySet()) {
            Object value = props.get(key);
            if (value != null) {
                ps.put(key.toString(), value.toString());
            }
        }
        this.setChangeLogParameters(ps);
    } catch (IOException ex) {
        LOGGER.error("", ex);
    }
}

}
package com.whatever.util;
导入java.io.File;
导入java.io.IOException;
导入java.util.HashMap;
导入java.util.Map;
导入java.util.Properties;
导入liquibase.integration.spring.SpringLiquibase;
导入org.apache.log4j.Logger;
导入org.springframework.core.io.FileSystemResource;
导入org.springframework.core.io.Resource;
导入org.springframework.core.io.support.PropertiesLoaderUtils;
公共类CustomLiquibase扩展了SpringLiquibase{
专用静态最终记录器=记录器
.getLogger(CustomLiquibase.class);
公共CustomLiquibase(字符串属性名称){
超级();
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibaseConfiguratore' defined in class path resource [spring/applicationContext.xml]: Invocation of init method failed; nested exception is liquibase.exception.LiquibaseException: Cannot find parser that supports classpath:liquibase/configuratore-db-changelog.xml
    at 
.....
Caused by: liquibase.exception.LiquibaseException: Cannot find parser that supports classpath:liquibase/configuratore-db-changelog.xml
    at liquibase.parser.ChangeLogParserFactory.getParser(ChangeLogParserFactory.java:61)
    at liquibase.Liquibase.update(Liquibase.java:107)
    at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:262)
package com.whatever.util;

import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

public class LiquibaseFactory {

private static boolean enabled = !StringUtils.equals(
        System.getProperty("liquibase.disable"), "true");

private static Logger log = Logger.getLogger(LiquibaseFactory.class);

public static CustomLiquibase createLiquibaseBean(DataSource dataSource,
        String changeLog, String propFileName) {

    log.info("dataSource is " + dataSource);
    log.info("changeLog is " + changeLog);
    log.info("propFileName is " + propFileName);

    CustomLiquibase customLiquibase = null;
    if (enabled) {

        log.info("creating customLiquibase ENABLED");

        customLiquibase = new CustomLiquibase(propFileName);
        customLiquibase.setDataSource(dataSource);
        customLiquibase.setChangeLog(changeLog);

    } else {

        log.warn("Liquibase has been disabled");

        log.warn("\n\n" + StringUtils.repeat("*", 80));
        log.warn(StringUtils.repeat("*", 80) + "\n\n");

    }
    return customLiquibase;
}

}
package com.whatever.util;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import liquibase.integration.spring.SpringLiquibase;
import org.apache.log4j.Logger;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

public class CustomLiquibase extends SpringLiquibase {

private static final Logger LOGGER = Logger
        .getLogger(CustomLiquibase.class);

public CustomLiquibase(String propertiesName) {

    super();
    LOGGER.info("propertiesName is " + propertiesName);

    Resource resource = new FileSystemResource(new File(propertiesName));
    try {
        LOGGER.info("resource is " + resource);

        Properties props = PropertiesLoaderUtils.loadProperties(resource);
        Map<String, String> ps = new HashMap<String, String>();
        for (Object key : props.keySet()) {
            Object value = props.get(key);
            if (value != null) {
                ps.put(key.toString(), value.toString());
            }
        }
        this.setChangeLogParameters(ps);
    } catch (IOException ex) {
        LOGGER.error("", ex);
    }
}

}