与Spring集成时自定义Liquibase更改错误:未知Liquibase扩展。你错过了类路径中的jar吗?

时间:2014-03-25 13:10:34

标签: spring liquibase

作为现有应用程序的数据库升级的一部分,已创建扩展AbstractChange的自定义Liquibase更改:

@DatabaseChange(name = "springBeanChange", description = "Runs a spring bean custom change", priority = ChangeMetaData.PRIORITY_DEFAULT)
public class SpringBeanChange extends AbstractChange {
    private String beanName;
    private String changeClass;

    @DatabaseChangeProperty(description = "Spring bean name (optional)")
    public String getBeanName() {
        return this.beanName;
    }

    public void setBeanName(final String beanName) {
        this.beanName = beanName;
    }

    @DatabaseChangeProperty(description = "Spring bean class")
    public String getChangeClass() {
        return this.changeClass;
    }

    public void setChangeClass(final String changeClass) {
        this.changeClass = changeClass;
    }

    private CustomTaskChange bean;

    @Override
    public boolean generateStatementsVolatile(final Database database) {
        return true;
    }

    @Override
    public String getConfirmationMessage() {
        return findBean().getConfirmationMessage();
    }

    @Override
    public SqlStatement[] generateStatements(final Database database) {
        try {
            findBean().execute(database);
        } catch (CustomChangeException e) {
            throw new UnexpectedLiquibaseException(e);
        }
        return new SqlStatement[0];
    }

    @SuppressWarnings("unchecked")
    private CustomTaskChange findBean() {
        Class<CustomTaskChange> requiredType = CustomTaskChange.class;
        if (this.changeClass != null) {
            try {
                Class<?> requestedType = Class.forName(this.changeClass);
                if (CustomTaskChange.class.isAssignableFrom(requestedType)) {
                    requiredType = (Class<CustomTaskChange>) requestedType;
                } else {
                    throw new UnexpectedLiquibaseException(
                            "Specified changeClass " + this.changeClass
                                    + " was not an instance of "
                                    + CustomTaskChange.class);
                }
            } catch (ClassNotFoundException e) {
                throw new UnexpectedLiquibaseException(
                        "Could not create change class", e);
            }
        }
        if (this.bean == null) {
            if (getBeanName() == null) {
                this.bean = SpringContextHolder.getInstance().getContext()
                        .getBean(requiredType);
            } else {
                this.bean = SpringContextHolder.getInstance().getContext()
                        .getBean(getBeanName(), requiredType);
            }
        }
        return this.bean;
    }

    @Override
    public ValidationErrors validate(final Database database) {
        try {
            return findBean().validate(database);
        } catch (NullPointerException p_exception) {
            return new ValidationErrors()
                    .addError("Exception thrown calling validate():"
                            + p_exception.getMessage());
        } catch (UnexpectedLiquibaseException p_exception) {
            return new ValidationErrors()
                    .addError("Exception thrown calling validate():"
                            + p_exception.getMessage());
        } catch (NoSuchBeanDefinitionException p_exception) {
            return new ValidationErrors()
                    .addError("Exception thrown calling validate():"
                            + p_exception.getMessage());
        } catch (BeanNotOfRequiredTypeException p_exception) {
            return new ValidationErrors()
                    .addError("Exception thrown calling validate():"
                            + p_exception.getMessage());
        } catch (BeansException p_exception) {
            return new ValidationErrors()
                    .addError("Exception thrown calling validate():"
                            + p_exception.getMessage());
        }
    }
}

然后在数据库更改日志XML文件中对其进行如下配置:

    <changeSet id="15" author="theauthor">
        <XXX:springBeanChange
            changeClass="XXX.XXX.XXX.upgrade.tasks.TaskUpgrade" />
    </changeSet>

在TaskUpgrade实现CustomTaskChange的情况下,返回的类在SpringBeanChange中调用getBean。

数据库更改日志文件还包含许多“普通”liquibase命令,例如addColumn。

然后编写了一个实际执行升级的自定义Java类(以下行显示了实际进行升级的重要代码行)。将应用程序部署到服务器后,手动执行此Java程序:

        Liquibase liquibase =
                new Liquibase(getChangeLogFile(), new ClassLoaderResourceAccessor(), new JdbcConnection(conn));
        if ("update".equalsIgnoreCase(command)) {
            liquibase.update(contexts);
        } else {
            throw new IllegalArgumentException("Unknown command " + command);
        }

这样可以正常工作并执行数据库升级。

我希望避免使用自定义Java程序来执行升级,并在应用程序启动时实际执行此操作。该应用程序已经使用了Spring,因此在Spring上下文初始化时升级是有意义的。

为此,我将以下内容添加到applicationContext文件中:

    <bean id="myLiquibase" class="liquibase.integration.spring.SpringLiquibase">
        <property name="dataSource" ref="dataSource" />
        <property name="changeLog" value="classpath:databaseChangeLog.xml" />
        <property name="contexts" value="test, production" />
    </bean>

但是,当应用程序启动时,我得到以下异常:

2014-03-25 13:02:16,097 [main] ERROR context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myLiquibase' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is liquibase.exception.ChangeLogParseException: Invalid Migration File: Unknown Liquibase extension: springBeanChange.  Are you missing a jar from your classpath?
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1488)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:549)
    at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
    at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1282)
    at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:518)
    at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:499)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
    at org.mortbay.jetty.Server.doStart(Server.java:224)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at XXX.XXX.XXX.demo.YYYDemo.main(YYYDemo.java:47)
Caused by: liquibase.exception.ChangeLogParseException: Invalid Migration File: Unknown Liquibase extension: springBeanChange.  Are you missing a jar from your classpath?
    at liquibase.parser.core.xml.XMLChangeLogSAXParser.parse(XMLChangeLogSAXParser.java:133)
    at liquibase.Liquibase.update(Liquibase.java:129)
    at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:291)
    at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:258)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1547)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1485)
    ... 22 more
Caused by: org.xml.sax.SAXException: Unknown Liquibase extension: springBeanChange.  Are you missing a jar from your classpath?
    at liquibase.parser.core.xml.XMLChangeLogSAXHandler.startElement(XMLChangeLogSAXHandler.java:495)
    at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
    at org.apache.xerces.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
    at org.apache.xerces.impl.xs.XMLSchemaValidator.emptyElement(Unknown Source)
    at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
    at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
    at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at liquibase.parser.core.xml.XMLChangeLogSAXParser.parse(XMLChangeLogSAXParser.java:99)
    ... 27 more
Caused by: org.xml.sax.SAXException: Unknown Liquibase extension: springBeanChange.  Are you missing a jar from your classpath?
    at liquibase.parser.core.xml.XMLChangeLogSAXHandler.startElement(XMLChangeLogSAXHandler.java:359)
    ... 39 more

我在Liquibase网站或其他任何地方都找不到任何关于我错过的JAR(如果我确实错过了JAR)或者其他任何内容缺失/未定义的任何帮助。

有没有人有任何想法?

提前致谢。

1 个答案:

答案 0 :(得分:2)

包含自定义扩展的jar是类路径中缺少的内容。我不使用Spring,所以我不知道它是如何设置类路径的,但是您可能需要将jar放在标准位置,以便Spring可以找到它,或者配置Spring类路径。 / p>