Connecting multiple datasources in spring boot with jpa

One db connects abc database and second db connects xyz database.

I created a configuration file for each datasource wherein i will declare the datasource, entitymanager and trasactionmanager for each database as well as the packages which will refer these .

@Configuration
@EnableJpaRepositories(basePackages = {
“com.abc.payment”}, entityManagerFactoryRef = “abcEntityManager”, transactionManagerRef = “abcTransactionManager”)
public class AbcDataSouceConfig {

@Bean(name = "datasource")
@Primary
public DataSource dbDataSource() {
}
@Bean(name = "abcTransactionManager")
@Primary
public PlatformTransactionManager dbTransactionManager() {
}
@Bean(name = "abcEntityManager")
@Primary
public LocalContainerEntityManagerFactoryBean dbEntityManager() {
}

}

The above AbcDataSouceConfig file has my primary datasouce configs for package “com.abc.payment” and as below i have created one more XYZDataSouceConfig which declares a different datasource configs for a different package “com.abc.order”

@Configuration
@EnableJpaRepositories(basePackages = {
“com.abc.order”}, entityManagerFactoryRef = “xyzEntityManager”, transactionManagerRef = “xyzTransactionManager”)
public class XYZDataSouceConfig {

@Bean(name = "datasource")
public DataSource dbDataSource() {
}
@Bean(name = "xyzTransactionManager")
public PlatformTransactionManager dbTransactionManager() {
}
@Bean(name = "xyzEntityManager")
public LocalContainerEntityManagerFactoryBean dbEntityManager() {
}

}

Advertisement

Why to use containers to distribute a Java application?

The Java ecosystem provides a standard format to distribute all Java classes that are part of the same application. You can package these classes as a JAR (Java Archive), WAR (Web Archive), and EAR (Enterprise Archive) that contains the front end, back end, and libraries embedded. So, Why do you use containers to distribute a Java application? Isn’t it already supposed to be easily portable between environments?

For a moment think about the development environment and some possible issues caused by the difference between it and the production environment:

  • Do you use Mac, Windows, or Linux? Have you ever faced an issue related to \ versus / as the file path separator?
  • What version of JDK do you use? Do you use Java 10 in development, but production uses JRE 8? Have you faced any bugs introduced by  JVM differences?
  • What version of the application server do you use? Is the production environment using the same configuration, security patches, and library versions?
  • During production deployment, have you encountered a JDBC driver issue that you didn’t face in your development environment due to different versions of the driver or database server?
  • Have you ever asked the application server admin to create a datasource or a JMS queue and it had a typo?

All the issues above are caused by factors external to your application, and one of the greatest things about containers is that you can deploy everything (for example, a Linux distribution, the JVM, the application server, libraries, configurations and, finally, your application) inside a pre-built container. Plus, executing a single container that has everything built in is incredibly easier than moving your code to a production environment and trying to resolve the differences when it doesn’t work. Since it’s easy to execute, it is also easy to scale the same container image to multiple replicas.

Jwt authentication

In microservice architecture, I wanted to authenticate in an api that it is receiving requests from a reliable resource without storing and retrieving any credentials on either side and JWT became the best fit.

JSON Web Token (JWT) is a popular way to authenticate/authorize users in a microservice architecture.

When a server receives a JWT, it can guarantee the data it contains can be trusted because it’s signed by the source. No middleman can modify a JWT once it’s sent.

Because of this, the server does not need to keep a database with the information needed to identify the user. For developers, this is great news — the server that issues the JWT and the server that validates it do not have to be the same. 

It’s important to note that a JWT guarantees data ownership but not encryption. The JSON data you store into a JWT can be seen by anyone that intercepts the token because it is not encrypted it’s just encoded which means you can use base64 decode and you will get the JSON object in clear.

Do note that for signed tokens information, though protected against tampering, is readable by anyone. Do not put secret information in the payload or header elements of a JWT unless it is encrypted.

Calling spring managed bean from a non spring managed class.

I had a spring managed bean with different dependencies, when I tried to call the same spring managed bean from a non spring managed class, I was getting null for all the dependencies declared in spring managed bean. I learnt that as I was calling spring managed bean from a non managed class I was not getting spring bean and so I took the following approach.

I declared a service class which implemented ApplicationContextAware like following:

@Service
public class serviceClass implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static <T> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }

}

and then using the following I fetched the springManaged class from the spring container into non spring managed class with all dependencies injected.

 SpringManaged springManaged = BeanUtil.getBean(SpringManaged.class);

A Bean in Spring

In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and managed by a Spring IoC container.

A class will only be managed by Spring container if it is declared as a spring bean using different annotations like @Component, @Repository etc, without it Spring container wont be able inject the class as a dependency into another class as spring is not aware of such classes not defined as spring bean.

Note: If you want to actually understand Spring best way is to atleast once debug its internal package and see how spring loads all the classes , it extensively uses java reflection api.

Dependency Injection

It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. 

So in simple terms before this we used to define any class in our methods like

class Example{

public void someMethod(){

DependentClass dependent=new DependentClass();

}

In DI above is not done instead through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method.

Spring Profiles

We use the @Profile annotation — When we have beans specific to a particular profile; the annotation simply takes the names of one (or multiple) profiles.

@Component

@Profile(“dev”)

public class RootConfig

The next step is to activate and set the profiles so that the respective beans are registered in the container.

profiles can be activated via the environment variable:

spring_profiles_active=dev

Enable hikaricp logs in spring boot

Add logging.level.com.zaxxer.hikari: DEBUG property to application.yml.

/**
* Log the current pool state at debug level.
*
* @param prefix an optional prefix to prepend the log message
*/
void logPoolState(String… prefix)
{
if (logger.isDebugEnabled()) {
logger.debug(“{} – {}stats (total={}, active={}, idle={}, waiting={})”,
poolName, (prefix.length > 0 ? prefix[0] : “”),
getTotalConnections(), getActiveConnections(), getIdleConnections(), getThreadsAwaitingConnection());
}
}

Above method called in HikariPool.java prints the info time to time from HouseKeeper class.

Surprise!!!! Integer.getInteger is not to retrieve any Integer value from a String.

I recently learned this that actually

 public static Integer getInteger(String nm) {
        return getInteger(nm, null);
    }

method in Integer class doesnt return Integer value from a string, for example

Integer.getInteger(“123”) will not return 123 but instead null .

This is because if we take a look in the internal code for above method

public static Integer getInteger(String nm, Integer val) {
    String v = null;
    try {
        v = System.getProperty(nm);
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    if (v != null) {
        try {
            return Integer.decode(v);
        } catch (NumberFormatException e) {
        }
    }
    return val;
}

The getInteger returns the integer value of the system property with the specified name.

So for “123”,

v = System.getProperty(nm); will look for some system property with name as 123 and in its absence will return null.

System properties are accessible through the method. The
System.getProperty(nm) . String value of this property is then interpreted as an integer value using Integer.decode(v) and Integer object representing this value is returned.