Spring Boot: Flyway migration before mybatis initialization - spring-boot

In my Spring Boot app I use Flyway for DB migrations and MyBatis together. Problem is that MyBatis is initialized before Flyway, so some DB operations are called (within #PostConstruct) before DB migration.
If I take a look into FlywayAutoConfiguration there is:
#AutoConfigureAfter({DataSourceAutoConfiguration.class, ...})
public class FlywayAutoConfiguration {
...
As I understand, I need override FlywayAutoConfiguration and add:
#AutoConfigureAfter({DataSourceAutoConfiguration.class})
#AutoConfigureBefore({MybatisAutoConfiguration.class})
public class FlywayAutoConfiguration {
...
Not sure how to do that. Thanks for any help.

I would declare a #Bean definition for flyway() and then another #Bean definition for whatever data source in your possession, making sure to initialize it after the flyway bean , which you can simply do by adding #DependsOn("flyway") annotation on your data source bean declaration.
This way you make sure whatever data init tasks launched by your data source will come after flyway has done its job.

Related

Binding specific sqlsessionfactory with #Mapper annotation with spring boot

TL;DR
When using MyBatis with Spring boot, is following step possible?
Create Datasource, SqlSessionFactory, SqlTransactionManager beans without mapperscan
Deploy 1 as library
import 2, create Mapper with beans declared in 1 with #Mapper annotation
Question
(First of all, apologize my poor english)
I'm creating mybatis datasource autoconfiguration library for my spring boot project.
Datasource will used at some applications, and they would have different mapper.
If mappers are already defined, creating DataSource, SqlSessionFactory and SqlTransactionManager beans with #MapperScan can bind Mapper and those beans.
But when case like this; DataSource, SqlSessionFactory, SqlTransactionManager beans declared,
and Mappers will created later, is possible binding specific beans with #Mapper annotation?
Those beans are default currently, so project would works.
But if another datasource added without mapper scan,
application initialization failed due to duplicate bean definition.
For some reasons, i prefer these done with mapper annotation(not mapper xml)
If any another advice for this design, looking forward to answer.
Thank you.

Using properties from application.properties while building bean in spring boot configuration annotated class?

We have properties defined in application.properties, is it appropriate to have the property pulled in a spring-boot #Configuration annotated class to be used for initializing the bean being created. Refer code snippet below
#Configuration
public class MyConfig {
#Value("${a.property.in.application.properties}")
public String aProperty;
#Bean
MyClass myClassInstance() {
return new MyClass(aProperty);
}
}
Simplest example would be creating a datasource instance with url, driver, username, password configured in the application.properties
Is it appropriate?
What could be the possible consequences of continuing to use in this manner?
I'm using this approach for different things like cors configurations. There are probably also disadvantages, but so far it has only had advantages for me. I think it's most times better to have config values outside of the code. That allows you, for example, to use different profiles (local/dev/int/prod). But I would recommend to encrypt things like passwords. I'm using Jasypt.

Using #ConfigurationProperties in Spring Boot Application doesn't work

I am using Spring Boot V 1.4.1 for a new application.
My app requires two JDBC data sources and I was following the example at http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources how to set it up.
My Spring beans configuration class is annotated with #EnableConfigurationProperties and my first bean is defined as
#Primary
#Bean
#ConfigurationProperties(prefix = "first.database")
DataSource qivsDB() {
return DataSourceBuilder.create().build();
}
, the second one accordingly. My application.properties file has properties defined like
first.database.url=jdbc:[redacted]
first.database.username=[redacted]
first.database.password=[redacted]
For reasons I not transparent to me during debugging this is failing to initialize: Cannot determine embedded database driver class for database type NONE - debug showed me that the builder does not have any properties set when calling build().
What did I miss here?
Before you do all the debugging part, you should have a look to the auto-configuration report. If you define your own DataSource there's no reason for Spring Boot to start looking at what it can do for your app. So, for some reasons, that definition of yours is not applied in your app and the default in Spring Boot still applies, doesn't find any JDBC url in the default namespace and attempt to start an embedded database. You should see in the auto-config report that the DataSourceAutoConfiguration still matches.
I am not sure the public keyword has anything to do with it, though you won't get custom meta-data for that key since we only scan for public methods.

Spring, Run task once when application started

My application is based on spring boot.
I want to create a task which should be run only once after application has been started.
Currently, I am looking into two solutions:
Using #Scheduled and boolean property which should determine whether the logic shold be run or not.
#Scheduled
public void method(){
if(method_run_propery){
//do something;
}
}
Using Quartz. But I have not used before.
Please, tell me what is the best approach to use in this case.
Spring has a #PostConstruct annotation to do exactly that. Runs once the bean has been initialized and all dependencies added.
If it has to be run once immediately after application is initialized, I would simply start it from the init method of a singleton bean. Spring ensures that at be time it will be run all dependant beans will have been initialized.
For example, assuming a Java annotation Spring configuration you could use something like:
#Bean(init_method="init")
class TaskLauncher {
#Autowired DependantBeanClass dependant Bean;
...
public void init() {
// execute or start the task, eventually using the autowired dependant beans
...
}
}
When the context is refreshed, Spring autowire everything, initializes the dependant beans and then will call once the init method of the TaskLauncher bean.
No need for #Scheduler nor Quartz if you only need to start something at Spring initialization time
One of the ways is to implement ApplicationListener
Once spring context is initialized, Your class which implements ApplicationListener
which will then have onApplicationEvent method will be invoked, your logic can go in this method.

Integrate Mongeez with Spring Boot and Spring Data MongoDB

I want to integrate Mongeez with my Spring Boot application and was wondering how to properly run Mongeez during application startup. Mongeez suggests creating a MongeezRunner bean. However, the challenge is to run Mongeez before any of the Spring Data initialization is happening, specifically, before the MongoTemplate instance is created. This is crucial because there might be changes in the database that prevent the application to start at all (e.g. changing index definitions).
My current approach is to provide the MongoTemplate bean myself, running Mongeez before creating it:
#Bean
public MongoTemplate mongoTemplate(Mongo mongo, MongoDbFactory mongoDbFactory,
MongoConverter converter) throws IOException {
// make sure that Mongeez runs before Spring Data is initialized
runMongeez(mongo);
return new MongoTemplate(mongoDbFactory, converter);
}
private void runMongeez(Mongo mongo) throws IOException {
Mongeez mongeez = new Mongeez();
mongeez.setMongo(mongo);
mongeez.setDbName(mongodbDatabaseName);
mongeez.setFile(new ClassPathResource("/db/migrations.xml"));
mongeez.process();
}
It works, but it feels like a hack. Is there any other way to do this?
After taking a look at Spring Boot's source code, it turns out that this problem isn't anything new. The FlywayAutoConfiguration for example has to make sure that Flyway (a migration tool for SQL-based databases) runs before any EntityManagerFactory beans are created. To achieve this the auto-configuration registers a BeanFactoryPostProcessor that dynamically makes every EntityManagerFactory bean depend on the Flyway bean, thus forcing Spring to create the Flyway bean first.
I solved my problem by creating a Spring Boot starter with a similar auto-configuration for Mongeez: mongeez-spring-boot-starter.

Resources