在静态工厂方法中创建SpringLiquibase bean时不能使用占位符

时间:2014-06-25 07:21:54

标签: spring liquibase applicationcontext

在Glassfish 2.1.1上运行Liquibase 2.0.5的Spring 3.1.0 - 从一位已经离去的同事那里继承了这个以这种方式构造SpringLiquibase bean的applicationContext.xml:

<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>

其中LiquibaseFactory是一个工厂,静态方法 createLiquibaseBean 生成的bean具有类

com.whatever.CustomLiquibase extends liquibase.integration.spring.SpringLiquibase

现在我需要参数化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>

为了设置参数的正确值,我浏览了SpringLiquibase的源代码,我看到了String changeLog:

/**
 * Sets a Spring Resource that is able to resolve to a file or classpath resource.
 * An example might be <code>classpath:db-changelog.xml</code>.
 */
public void setChangeLog(String dataModel) { ... }

阅读完之后,我将原始字符串放在我的属性文件中。

tgo.liquibase.changelog.filename=classpath:liquibase/configuratore-db-changelog.xml

并将道具声明为:

<context:property-placeholder location="file:///opt/whatever/custom_properties.properties" />

但是bean在创建过程中失败了。错误信息是:

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)

显然,当XML中存在普通字符串时,会找到解析器。我放置占位符的那一刻,解析器就在那里找到了。但看起来占位符是正确解析的,至少在屏幕上......

我尝试了一些变化:

  • 在文件中放置文件:/absolute/path/to/configuratore-db-changelog.xml
  • 在属性中放置classpath *:liquibase / configuratore-db-changelog.xml
  • 把属性&quot; index = 0,1,2&#39;而不是&#39; name&#39; inside tag constructor.arg

但问题仍然存在。

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

这是完整的堆栈追踪: [#|2014-06-25T09:19:54.860+0200|SEVERE|sun-appserver2.1|javax.enterprise.system.container.web|_ThreadID=12;_ThreadName=pool-1-thread-6;_RequestID=36e46602-c248-4e54-844e-6e5e11225bb8;|WebModule[/FastwebSme]PWC1275: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener 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 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:384) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4632) at org.apache.catalina.core.StandardContext.start(StandardContext.java:5312) at com.sun.enterprise.web.WebModule.start(WebModule.java:353) at com.sun.enterprise.web.LifecycleStarter.doRun(LifecycleStarter.java:58) at com.sun.appserv.management.util.misc.RunnableBase.runSync(RunnableBase.java:304) at com.sun.appserv.management.util.misc.RunnableBase.run(RunnableBase.java:341) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) 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) at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:245) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452) ... 24 more |#] 这里是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);
    }
}

}

0 个答案:

没有答案