Spring Load database properties - spring

I would like to load database values in runtime, when spring application launch.
public List<MyBean> beanValues() {
List<MyBean> value; // fetch all values from database
}

Use spring bean. So that data will be loaded when application launch up
#Configuration
class BeanList {
#Bean
public List<MyBean> beanValues() {
/*
List<MyBean> result = dao.getAllBeans(); // use your dao to fetch all
// values from database and store it in a variable
*/
}
}
// now to access the values use Autowired annotation
#Component
class MyApp {
#Autowired
private List<MyBean> beanValues;
}

Related

Spring - Create scheudled tasks from external files

I have a spring boot application that reads configuration files from storage.
I want that for each file - a scheduled task will be created.
The files are read and stored into a Pojo MyFileData and i have a bean that returns List<MyFileData>
I have read about SchedulingConfigurer but I don't understand how i can get the bean value inside the configureTasks method.
#Configuration
public class FirstConfigFile {
#Bean
public List<MyFileData> myFileDataList() {
List<MyFileData> myConfigFiles = new ArrayList();
// read from storage
return myConfigFiles;
}
}
#Configuration
public class SecondConfigFile implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// how do i get the myFileDataList bean?
for(MyFileData fd : myFileDataList) {
// create scheduled tasks and regiester them in the taskRegistrar
}
}
}
Note: I prefer to keep the #Configuration classes separate.
You can #Autowired that List as it is declared as #Bean.

How do I autowire OrmLite DAO instances into Spring Controllers?

So I'm using SpringBootApplication to create a quick server application.
I want to have persistence in this application as well, so I added OrmLite to handle my SQLite database.
Instantiating OrmLite DAOs requires a ConnectionSource to the database. How do I #Autowire this instantiated DAO with the connectionSourceto my controller handling requests, so that I can return whatever they requested from the database? I also have a databaseHelper class that creates the connection to the database, it get instantiated in the application main method.
For example the controller:
#RestController
public class GreetingController {
#AutoWired
GreetingDao greetingDao;
//how does this instance have the connectionSource Dao to the database?
}
DAO:
#Component
public class GreetingDao {
Dao<int, Greeting> greetingDao;
public GreetingDao(ConnectionSource connectionSource) {
greetingDao = Dao.createDao(connectionSource, Greeting.class);
}
}
Okay so after reading a bit further on this, I realized that I can just set default constructors for my DAO classes, and then when my application main is called, I just set the connectionSource for my DAO's in the ApplicationContext.
Then when I have #Autowire for my DAOs inside the controller classes, they will have the same instance that I set my connectionSource to.
//inside #SpringBootApplication class
public void main(String [] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args)
DatabaseHelper dbHelper = context.getBean(DatabaseHelper.class)
dbHelper.connect();
GreetingAccessor greetingAccessor = context.getBean(GreetingAccessor.class)
greetingAccessor.createDao(dbHelper.getConnectionSource);
}
//inside GreetingAccessor
public void createDao(ConnectionSource connectionSource) {
greetingDao = DaoManager.createDao(connectionSource, Greeting.class);
}

Binding #ConfigurationProperties to builder used to create bean

I'm creating multiple Caffeine caches like:
#Bean
public Cache<String, Customer> customerCache() {
return Caffeine.newBuilder()
.maximumSize(10_000)
// other config settings
.build(..);
}
Now I would like to use something like a #ConfigurationProperties(prefix = "cache.customer") to set the builder config options.
Where a application property cache.customer.maximum-size: 1000 exists.
Is there something smart I can do to map the #ConfigurationProperties to the Caffeine builder?
For future readers here is code I used to use Spring Boot's #ConfigurationProperties to configure a Caffeine Cache:
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
/**
* Base class for configuration of a Caffeine {#link Cache}
*/
public class CaffeineCacheProperties {
private Integer maximumSize;
// TODO: Add additional properties + getters and setters.
public Integer getMaximumSize() {
return maximumSize;
}
public void setMaximumSize(final Integer maximumSize) {
this.maximumSize = maximumSize;
}
public Caffeine initializeCacheBuilder() {
Caffeine cacheBuilder = Caffeine.newBuilder();
if (maximumSize != null) {
cacheBuilder.maximumSize(maximumSize);
}
// TODO: Configure additional properties.
return cacheBuilder;
}
}
.
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* The cache {#link Configuration} class.
*/
#Configuration
public class CacheConfig {
#Bean
#ConfigurationProperties("cache.customer")
public CaffeineCacheProperties customerCacheProperties() {
return new CacheProperties();
}
#Bean
public Cache<String, Customer> customerCache() {
return customerCacheProperties().initializeCacheBuilder().build();
}
// TODO: Add other caches.
}
And then add a application property like:
cache.customer.maximum-size: 1000
You can do something similar to what the boot team has done with DataSourceProperties:
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java
You bind your properties into a property class and then use a method on that properties class to create your builder.
Here is a different example where we are binding both the properties and a data source to the same root:
#Bean
#ConfigurationProperties("datasource.task")
public DataSourceProperties taskDataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = {"taskDataSource"}, destroyMethod="")
#ConfigurationProperties("datasource.task")
#ConditionalOnMissingBean(name="taskDataSource")
public DataSource taskDataSource() {
return taskDataSourceProperties().initializeDataSourceBuilder().build();
}
You can use #ConfigurationProperties(prefix = "cache.customer") on top of your CacheConfig class (A configurations class) where you can easily bind the application properties to your Cache class by using #EnableConfigurationProperties(CacheConfig.class).
So now you can auto wire the CacheConfig class to your Cache class and save it as a private attribute in your cache class. And then you can use that configurations through builder like
#Bean
public Cache<String, Customer> customerCache() {
return Caffeine.newBuilder()
.maximumSize(cacheConfig.getMaximumSize())
// other config settings
.build(..);
}

How to create a dynamic datasource using SpringBoot

I have a springboot application, with its own datasource (let's call DB1) set on properties working fine.
But this application needs do configure a new datasource (DB2), using some parameters the user have informed before and stored in DB1.
My idea is to create a named bean, so a specific part of my application can use to access DB2 tables. I think it is possible to do that by restarting the application, but I would like to avoid it though.
Besides, I need that some part of my code use the new datasource (spring data jpa, mappings, and so on). I don't know if this matter, but it is a web application, so I cannot create the datasource only for the request thread.
Can you help me?
Thanks in advance.
Spring has dynamic datasource routing if that's where you are headed. In my case it is the same schema (WR/RO)
public class RoutingDataSource extends AbstractRoutingDataSource {
#Autowired
private DataSourceConfig dataSourceConfig;
#Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
public enum DbType {
MASTER, WRITE, READONLY,
}
Then you need a custom annotation and an aspect
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface ReadOnlyConnection {
}
#Aspect
#Component
#Order(1)
public class ReadOnlyConnectionInterceptor {
Pointcut(value = "execution(public * *(..))")
public void anyPublicMethod() {}
#Around("#annotation(readOnlyConnection)")
public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable {
Object result = null;
try {
DbContextHolder.setDbType(DbType.READONLY);
result = proceedingJoinPoint.proceed();
DbContextHolder.clearDbType();
return result;
} finally {
DbContextHolder.clearDbType();
}
}
}
And then you can act on you DB with the tag #ReadOnlyConnection
#Override
#Transactional(readOnly = true)
#ReadOnlyConnection
public UnitDTO getUnitById(Long id) {
return unitRepository.findOne(id);
}
An example can be found here: https://github.com/afedulov/routing-data-source.
I used that as a basis for my work although it is still in progress because I still need to resolve runtime dependencies ( i.e. hibernate sharding ).

Issue while loading multiple Spring JPA context

We are develpoing a application for fetching data from two separate databases[Mssql/Sybase].We are using Spring JPA (OpenJPA implementation) to interact with both databases. We used two different context files(Mssqlcontext.java and SybaseContext.java) for each DB. We have set separate profile name in context files(MsSqlProfile/SybaseProfile). We needs to conditionally load the context files based on our configuration. But the details of which database is configured is specified in an seperate configuration xml file. XML file is read as part of a bean. We are loading context using #import annotation. JPA expects to give correct DB details while loading a context. But the context is imported before reading the configuration file. So we can't provide the correct database details.
The main problem that are trying to solve is that the Spring application should not crash if any of the database is not configured.
We tried to load the configuration bean before importing the context by implementing the following
Condition
ImportSelector
DeferredImportSelector
Ordered
However these are not working as expected.
Sample code
public class SampleServiceInitializer implements WebApplicationInitializer
{
/**
* Register the Spring configuration.
*/
public void onStartup(ServletContext container) throws ServletException
{
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
....
....
ctx.register(SampleServiceConfiguration.class);
....
....
}
}
#Import(SampleControllerConfiguration.class)
public class SampleServiceConfiguration
{
#Bean(name = configurationBean)
#Scope("singleton")
public ConfigRegistration getConfiguration()
{
ConfigRegistration config = new ConfigRegistration();
config.init();
// Here we read the configurations and set the profile name(SyabseProfile/MssqlProfile)
return config;
}
}
#Import({ SampleDataSourceConfiguration.class, SampleRequestorConfiguration.class })
public class SampleControllerConfiguration
{
....
....
}
#Import({ MSSqlContext.class, SybaseContext.class })
public class SampleDataSourceConfiguration
{
....
....
}
#Configuration
#Profile(MsSqlProfile)
....
....
public class MSSqlContext
{
....
....
}
#Configuration
#Profile(SybaseProfile)
....
....
public class SybaseContext
{
....
....
}
In the above sample code MSSqlContext and SybaseContext is initialized before the configurationBean.

Resources