Generics enabled Spring Service Factory Pattern
In this post, we’re going to see how to leverage spring container to auto-populate factory bean for different types of implementation for a common service.
To illustrate it, let’s pick up a scenario and run through it.
AccountService is a service interface which defines the account related service. Assume there are a couple of account types, Checking and Savings. So we need to have two different implementations of account service. One for checking and the other one is for savings.
package com.learnjava.Spring.Factory.Bean; import java.math.BigDecimal; public interface AccountService { AccountType getAccountType(); BigDecimal getInterestRate(); }
Checking Account Service Impl:
package com.learnjava.Spring.Factory.Bean; import java.math.BigDecimal; import org.springframework.stereotype.Service; @Service public class CheckingAccountService implements AccountService, RegisterBean<AccountType>{ @Override public AccountType getAccountType() { return AccountType.CHECKING; } @Override public BigDecimal getInterestRate() { // TODO Auto-generated method stub return BigDecimal.ZERO; } @Override public AccountType getRegisterId() { return AccountType.CHECKING; } }
Savings Account Service Impl:
package com.learnjava.Spring.Factory.Bean; import java.math.BigDecimal; import org.springframework.stereotype.Service; @Service public class SavingsAccountService implements AccountService, RegisterBean<AccountType>{ @Override public AccountType getAccountType() { return AccountType.SAVINGS; } @Override public BigDecimal getInterestRate() { return BigDecimal.ONE; } @Override public AccountType getRegisterId() { return AccountType.SAVINGS; } }
Now, we’ve service implementations. If you closely look at both of the implementations, both have implemented RegisterBean along with AccoutService. Register Bean is an interface that makes this implementation looked up by the corresponding service factory bean at runtime. Also, the implementation should override getRegisterId method that has to return a value type to be looked up.
Now, let’s write a factory class that is going to be super-simple with the help of generics when extends the ServiceFactory which has default implementation to look up and add the instances of implementation to its instance map by checking RegisterBean and AccountService in the spring application context and uses the type value returned by getRegisterId.
package com.learnjava.Spring.Factory.Bean; import org.springframework.stereotype.Service; @Service public class AccountServiceFactory extends ServiceFactory<AccountType,AccountService> { }
Time to Autowired Service Factory and invoke the Account Service implementation by type.
package com.learnjava.Spring.Factory.Bean; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class PrintDetailBean { @Autowired AccountServiceFactory accountServiceFactory; @PostConstruct public void printAccountDetail() { System.out.println("Checking Account Details..."); AccountService accountService = accountServiceFactory.getInstance(AccountType.CHECKING); System.out.println("Account Tye : "+accountService.getAccountType()); System.out.println("Account Type Interest Rate : "+accountService.getInterestRate()); System.out.println("Savings Account Details..."); accountService = accountServiceFactory.getInstance(AccountType.SAVINGS); System.out.println("Account Type : "+accountService.getAccountType()); System.out.println("Account Type Interest Rate : "+accountService.getInterestRate()); } }
As you see above, we can easily lookup service implementation by type. Once we have a reference to it, we can call the corresponding implementation.
This post was originally written in Medium. Please find it here.
The complete project is available at the below link.
Happy Learning!!!