Spring boot multiple datasource to call same service without #Qualifier - spring

I have a requirement where we will be using multiple darasources to call same dao method. The databse schema is all same.
Currently we are using datasource properties in application.properties and using below code to get datasource and call respective dao method with that.
#Autowired
private DataSource ds;
ds.getAllUsers(){....};
Now I will have multiple beans like below:
#Bean(name="comp1")
#ConfigurationProperties("ds.comp1")
public DataSource comp1DataSource(){
return new DataSourceBuilder.create().build();
}
I can use #Qualifer to point to respective datasource bean, but I want to call same method getAllUsers with all datasource beans. So I was thinking to have all datasource in a list and then iterate it with to call the method.
Please let me know how to do it

You can inject automatically all beans with the same type using an array or list with #Autowired (by field or constructor). The implementation/configuration will dependent on how you are using the datasource (Spring Data Repository, JdbcTemplate or others).

Related

Autowired Domain/Entity classes retains Old values

I have a mapper class for an incoming Event message.
Once the event message comes to the application, the mapper class sets the values in the entity object and saves it in the Database.
I have Autowired the entity object in my mapper class.
Whenever a new event comes in, the autowired entity object is still having the Old/previous values.
Is autowiring of Domain/Entity object possible in this case or I should go with 'New' keyword instead of Autowiring as Spring bean.
I see some posts about using #Configurable. I am not sure which is the best coding practice in this case?
#Service
public class LegacyEventMapper {
#Autowired
private LegacyEvent legacyEvent;
#Autowired
private LegacyEntity legacyEntity;
public void mapLegacyNotificationDetails(LegacyScheduleEvent body) throws Exception {
//Setting the values into the Entity object
Thanks
I have no idea why you actually want to #Autowire an #Entity and make it spring aware. This is wrong. You can do it, but it makes absolutely no sense.
What you actually want to do is create a new LegacyEntity (via the new LegacyEntity) and save that instance to DB.
What you have read via #Configurable is the other way around - you inject a spring bean/service into an Entity.
I think We can #Autowire an #Entity class. But then we need to mention in Entity class that it is of Request scope
#Entity
#Scope(scopeName=WebApplicationContext.SCOPE_REQUEST, proxyMode=ScopedProxyMode.TARGET_CLASS)
public class LegacyEntity {
I am not sure if using the new keyword is the better approach instead of autowiring an Entity class?

What is the point of using #Autowired with new keyword?

I inspect some autoconfiguration classes from Spring boot.
In LiquibaseAutoConfiguration.class i noticed that LiquibaseProperties is autowired and at the same time created using new operator:
#Autowired
private LiquibaseProperties properties = new LiquibaseProperties();
#Autowired
private ResourceLoader resourceLoader = new DefaultResourceLoader();
This does not apply for all configuration classes, i also noticed this in JooqAutoConfiguration. Why new operator is used here?
It's only really of any use with #Autowired(required=false). In that case the instance that's been created by new would be used as a default value if an instance was not available for injection.
In the example you've shown an injected instance is always required so the instance created bynew will either be replaced with injected instance or a failure will occur if there was no instance to inject. In short it's redundant and the code could have been written like this:
#Autowired
private LiquibaseProperties properties;
#Autowired
private ResourceLoader resourceLoader;
Spring Boot 1.4 has fixed this by moving to constructor injection. Support for constructor injection in configuration classes was introduced in Spring Framework 4.3. The code in question now declares the fields as final and assigns their values in the constructor.
If you think about the construction of the object there is a period of time where that field would otherwise be null if the new operator was not used. I tried to find a diagram that showed the lifecycle of a managed bean but only found the documentation around the callbacks (Spring Reference).
Spring will normally instantiate the bean with the default constructor and do the "normal" things to the object (initialize fields). So in this case the fields get assigned new instances of the classes for those fields. Then Spring comes along and autowires the fields based on the instance of the class that is being managed within the ApplicationContext.
It does look odd but it may be due to some initialization within the class where a default properties and resource loader objects have to exist before Spring can do its autowiring?

spring/tomcat-jdbc pool - new connection listener

I am using tomcat-jdbc pool in default spring-boot setup. I would like to run some custom Java code each time new JDBC connection is established in the pool and before it is used for the first time. How to do it, and if there are several possibilities which one is the best?
To extend already accepted answer, you can use Spring AOP without full AspectJ if you use pointcut as this one:
#AfterReturning(pointcut = "execution(* org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection())")
public void afterConnectionEstablished() {
...
}
Well, I can think of two options:
Create your own wrapper class - either by extending Tomcat's DataSource class or by implementing Java's DataSource interface and delegating to the wrapped DataSource - and then add the logic you want to the desired methods and register a bean in a #Configuration class by manually instantiating your tomcat-jdbc DataSource (for examples on how to do so, refer to DataSourceConfiguration.Tomcat class) and wrapping it with your class.
Create an aspect and use Spring's AOP support to intercept calls to getConnection. Since DataSourceclass is in the javax package, I think you'll have to use AspectJ, and for some examples refer to this link
My suggestion would be to go with the first option, it should give you fewer headaches, here's a small example how you'd define your wrapper bean:
#Bean
public DataSource dataSource(DataSourceProperties properties) {
return new MyDataSourceWrapper(tomcatDataSourceFrom(properties));
}
private org.apache.tomcat.jdbc.pool.DataSource tomcatDataSourceFrom(
DataSourceProperties properties) {
// manual instantiation like in DataSourceConfiguration.Tomcat class
}

Flush MyBatis Cache externally (outside of mapper)

I'm using MyBatis with second level cache activated via <cache/> in xml mapper files.
Suppose I want to interact with the underlying DB/DataSource decoupled from MyBatis, for instance via direct jdbcTemplate.
How can I assure, that the MyBatis cache gets flushed appropriateley when I Insert/Update/Delete via jdbcTemplate on a table for that MyBatis holds cached query results.
In other words, how can I force MyBatis to flush its cache from outside of MyBatis mappers for certain cache namespace?
I'm aware of #Options(flushCache=true) annotation, but this seems not to work outside of mapper interfaces.
you can get cache from configuration and then get by namespace and clear it.
#Resource
SqlSessionFactory sqlSessionFactory;
public void clearCacheByNamespace(){
Configuration config = sqlSessionFactory.getConfiguration();
Cache cache = config.getCache("com.persia.dao.UserInfoMapper");
if(cache != null){
cache.clear();
}
}
Hi i have used another approach, because we used spring. Use autowire the Session implementation and call appropriate method
public class SomeServerClass{
#Autowired
private org.mybatis.spring.SqlSessionTemplate sqlSessionTemplate;
private void someClearMethod(){
sqlSessionTemplate.clearCache();
}
}
If I use interface org.apache.ibatis.session.SqlSession it refers to same instance

Spring+hibernate+jpa how does it work?

In the new project that I have joined, they keep using the terms Hibernate and JPA interchangeably. So, I tried to dive down into the code and try to understand how this whole thing works (I am new to Spring, JPA and Hibernate world). I'll try to put the code here for better understanding:
1) There is a #Configuration class where they have the following:
#Resource
private HibernateJpaVendorAdapter hibernateOracleJpaVendorAdapter;
LocalContainerEntityManagerFactoryBean entityManager =
new LocalContainerEntityManagerFactoryBean();
entityManager.setJpaVendorAdapter(hibernateOracleJpaVendorAdapter);
entityManager.setPersistenceUnitName("abc");
.
.
So, in this configuration class, we are returning an EntityManagerFactory.
2) Then there is a persistor class marked #Persistor, where a method of repository is invoked (for example, for a save operation):
blahblahRepository.save(blahblahEntity, abcdef);
3) Finally there is a repository class which is annotated #Repository. Then again, they have this piece of code:
#PersistenceContext(unitName = "same as the name in persistence.xml")
protected EntityManager entityManager;
The "save" method wraps around the persist method of JPA:
getEntityManager().persist(entityObject);
My questions are as follows:
1) There is no word about Hibernate other than in the hibernateJpaVendorAdapter. I searched the entire workspace and it showed just 3 occurences of the word hibernate, all in the configuration file.
2) From whatever knowledge I have, one should use either an EntityManagerFactory or an EntityManager but we are doing both?
Hibernate is one of the implementations of the JPA spec. Since your project chose Hibernate as its JPA implementation, it uses the JPA API, which delegates the Hibernate. Just like when you use the JDBC API, which delegates to a specific Oracle or PostgreSQL driver.
EntityManagerFactory, as its name indicates, is a factory for EntityManager. I don't see why you wouldn't use both. EntityManager is the main interface of the JPA API, used to execute all database operations (find, persist, merge, query, etc.). EntityManagerFactory must be configured before asking it to create an EntityManager.

Resources