作为现有应用程序的数据库升级的一部分,已创建扩展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)或者其他任何内容缺失/未定义的任何帮助。
有没有人有任何想法?
提前致谢。
答案 0 :(得分:2)
包含自定义扩展的jar是类路径中缺少的内容。我不使用Spring,所以我不知道它是如何设置类路径的,但是您可能需要将jar放在标准位置,以便Spring可以找到它,或者配置Spring类路径。 / p>