现在有的人在项目中引入了Liquibase来帮助管理数据库,liquibase是什么在此就不多赘述了,主要说一下liquibase遇到PostConstruct我们应该如何解决.
首先说为什么会遇到这个问题,这个问题是如何出来的,这里以SpringBoot项目为例进行说明,当我们在项目中引入Liquibase后你配置好一些changeLog位置以及其它配置信息后你启动项目时,Liquibase是自动启动的,如果项目中没有使用到PostContruct的话那将毫无问题,但是如果你使用到了那就会遇到一些问题,假如说你在PostContruct中做了数据库的查询然后放入缓存中,那么问题就来了,Liquibase的执行顺序是在PostContruct之后的,那么就会报错说找不到对应的表.
如何解决:
遇到这样的问题我们可以将Liquibase的自动启动修改为手动启动,然后通过Spring的生命周期在一个PostContruct之前的阶段来手动执行Liquibase,这样就能解决这个问题了.
在bean创建的生命周期中在初始化bean的时候会判断是否有实现了BeanPostProcessor 接口的方法,会在初始化之前执行postProcessBeforeInitialization前置方法,在初始化之后执行postProcessAfterInitialization后置方法
![](https://i-blog.csdnimg.cn/blog_migrate/741effd0f22ead9f47e96655f81b5db9.png)
通过实验发现PostContruct是在前置方法之后,后置方法之前执行,也就是 前置方法 > PostContruct > 后置方法
这样我们就可以通过实现这个接口来在PostContruct之前创建好表就不会报错说找不到对应的table了
当然你可以在类中的构造器中调用你也可以在前置方法中调用都是可以的,下面上代码
@Component
public class LiquibaseConfig implements BeanPostProcessor {
private final DataSource dataSource;
public LiquibaseConfig(DataSource dataSource) {
this.dataSource = dataSource;
run("liquibase/master.xml");
}
public void run(String file) {
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader = currentThread.getContextClassLoader();
ResourceAccessor threadClFO = new ClassLoaderResourceAccessor(contextClassLoader);
ResourceAccessor clFO = new ClassLoaderResourceAccessor();
ResourceAccessor fsFO = new FileSystemResourceAccessor();
try (Connection connection = dataSource.getConnection()) {
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
Liquibase liquibase = new Liquibase(file, new CompositeResourceAccessor(clFO, fsFO, threadClFO), database);
liquibase.setChangeLogParameter("now", database.getCurrentDateTimeFunction());
liquibase.update("");
// 关闭数据库
database.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}