I'd like to use two configurations of Liquibase in current project. The default configuration I'd like to use for DDL changes and second one for custom inserts where changelog will be in another location.
If I configure SpringLiquibase
the default autoconfiguration will be skipped due to @ConditionalOnClass(SpringLiquibase.class)
annotation in LiquibaseAutoConfiguration
class.
How can I use default autoconfiguration + my custom? Can I overwrite the @ConditionalOnClass annotation somehow? Or maybe is there way how to tell Liquibase that I have another changelog outside of application and run it only if it's present?
Thanks
edit:
This could be the solution for my problem, however I have problem with loading external files (files outside of classpath) in liquibase.
@Configuration
@EnableConfigurationProperties(LiquibaseProperties.class)
public class LiquibaseConfiguration {
@Bean
SpringLiquibase liquibase(DataSource dataSource, LiquibaseProperties properties) {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setChangeLog(properties.getChangeLog());
liquibase.setContexts(properties.getContexts());
liquibase.setDataSource(dataSource);
liquibase.setDefaultSchema(properties.getDefaultSchema());
liquibase.setDropFirst(properties.isDropFirst());
liquibase.setShouldRun(properties.isEnabled());
liquibase.setLabels(properties.getLabels());
liquibase.setChangeLogParameters(properties.getParameters());
liquibase.setRollbackFile(properties.getRollbackFile());
return liquibase;
}
@Bean
SpringLiquibase commandInitializerLiquibase(DataSource dataSource,
@Value("${docu.system.initializer.command.liquibase.changeLog}") String changeLogPath,
@Value("${docu.system.initializer.command.liquibase.contexts}") String contexts) {
File changeLog = new File(changeLogPath);
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(dataSource);
liquibase.setContexts(contexts);
liquibase.setIgnoreClasspathPrefix(true);
liquibase.setChangeLog(changeLog.getAbsolutePath());
liquibase.setShouldRun(changeLog.exists());
//liquibase.setResourceLoader(liquibaseResourceLoader());
addPathToClassloader(changeLogPath);
return liquibase;
}
}
If you want to use Spring Boot autoconfigured Liquibase feature then you can have only one SpringLiquibase
bean in your context.
This is because of @ConditionalOnMissingBean(SpringLiquibase.class)
annotation in LiquibaseAutoConfiguration
class. Spring's conditional feature searches for SpringLiquibase
instances and it's subclasses instances, so extending SpringLiquibase
class won't fix that problem.
There is no good way to override LiquibaseAutoConfiguration
.
In that case you have 3 solutions which could solve your problem:
1) Implement two separate Liquibase bean configurations:
@Configuration
public class LiquibaseConfiguration {
@Autowired
private DataSource dataSource;
//define this property in your embedded properties file or use spring's default
@Value("${liquibase.change-log}")
private String defaultLiquibaseChangelog;
@Bean
public SpringLiquibase liquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(dataSource);
liquibase.setChangeLog(defaultLiquibaseChangelog);
// Configure rest of liquibase here...
// ...
return liquibase;
}
}
and
@Configuration
public class LiquibaseConfiguration2 {
@Autowired
private DataSource dataSource;
//optional, define it in external configuration or through command line param
@Value("${liquibase.change-log-additional:#{null}}")
private String additionalLiquibaseChangelog;
@Bean(name = "additionalLiquibase")
public SpringLiquibase liquibase() {
if (additionalLiquibaseChangelog != null) {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(dataSource);
liquibase.setChangeLog(additionalLiquibaseChangelog);
// Configure rest of liquibase here...
// ...
return liquibase;
}
return null;
}
}
2) Use Liquibase
instead of SpringLiquibase
for manually configured liquibase instance
Use one autoconfigured SpringLiquibase
and one pure Liquibase
configuration instead of SpringLiquibase
(You will need to manually run your migrations and handle other stuff which is implemented in SpringLiquibase
)
3) Use only one SpringLiquibase instance
Use combination of Liquibase's changelogParameters
(http://www.liquibase.org/documentation/changelog_parameters.html), include
tag (http://www.liquibase.org/documentation/include.html) and only one SpringLiquibase
instance.
Example implementation:
Liquibase bean configuration
@Configuration
public class LiquibaseConfiguration {
@Autowired
private DataSource dataSource;
//define this property in your embedded properties file or use spring's default
@Value("${liquibase.change-log}")
private String defaultLiquibaseChangelog;
//define this property in your embedded properties file
@Value("${liquibase.extended-change-log}")
private String extendedLiquibaseChangelog;
//optional, define it in external configuration or through command line param
@Value("${liquibase.data-change-log:#{null}}")
private String liquibaseDataChangelog;
@Bean
public SpringLiquibase liquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(dataSource);
if (liquibaseDataChangelog != null) {
//here you can check if file exists...
Map<String, String> liquibaseChangelogParameters = new HashMap<>();
liquibaseChangelogParameters.put("liquibaseExternalDataChangelogPath", liquibaseDataChangelog);
liquibase.setChangeLog(extendedLiquibaseChangelog);
liquibase.setChangeLogParameters(liquibaseChangelogParameters);
} else {
liquibase.setChangeLog(defaultLiquibaseChangelog);
}
// Configure rest of liquibase here...
// ...
return liquibase;
}
}
changelog.xml (liquibase.change-log)
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.3.xsd">
<include relativeToChangelogFile="true" file="changelog-master.xml"/>
</databaseChangeLog>
changelog-with-external-data.xml ( liquibase.extended-change-log )
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.3.xsd">
<include relativeToChangelogFile="true" file="changelog-master.xml"/>
<include relativeToChangelogFile="false" file="${liquibaseDataChangelogPath}"/>
</databaseChangeLog>
Remember that having separate changelogs could be dangerous. You have to make sure that your changelogs are independent:
Included change-logs are run in the order they are found so care does need to be taken to make sure that the included changelogs are either completely independent, or that any required changelogs are run first.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With