99% of my dependency is manage with DI pattern via @Autowired Spring annotation.
Nevertheless in a particular scenario, I can't determine which implementation to be used until run-time.
The most known case, is the multiple implementation of parsers.
The first solution is to used multiple @Autowired (ugly mode)
Interface Parser {
<T> T parse();
}
@Component("JsonParser")
class JsonParser implements Parser {
...
}
@Component("XmlParser")
class XmlParser implements Parser {
...
}
class MyService {
@Autowired
@Qualifier("XmlParser")
Parser xmlParser;
@Autowired
@Qualifier("JsonParser")
Parser jsonParser;
...
}
But if I have a large number of implementation that can be not acceptable.
The second solution is to used ServiceLocator from Spring
interface ParserServiceLocatorFactory {
public Parser getParser(String parserName);
}
interface Parser {
<T> T parse();
}
@Component("JsonParser")
class JsonParser implements Parser {
...
}
@Component("XmlParser")
class XmlParser implements Parser {
...
}
class MyService {
@Autowired
ServiceFactory parserServiceLocatorFactory;
void exampleMethod() {
Parser xmlParser = parserServiceLocatorFactory.getParser("XmlParser");
}
}
This way to do seems right to me but compared with the third solution?
The third solution is to used pure factory pattern and inject it.
@Component
public ParserFactory {
Parser getParser(String parserName) {
...
}
}
interface Parser {
<T> T parse();
}
@Component("JsonParser")
class JsonParser implements Parser {
...
}
@Component("XmlParser")
class XmlParser implements Parser {
...
}
class MyService {
@Autowired
ParserFactory parserFactory
void exampleMethod() {
Parser xmlParser = parserFactory.getParser("XmlParser");
}
}
If you have pro/con for the previous solutions, or even better solution for my problem?
PS: it's pseudo code I may miss some small things :)
With Spring Boot's powerful dependency injection, Factory pattern comes to the rescue when different sub types of objects are needed.
Difference between Dependency Injection and Factory PatternIt requires both a dependent object and a factory object to work properly. DI makes the unit tests easier. It does not require boilerplate code. The factory pattern requires the object you want to test, the factory object, and the dependent object.
In this tutorial, we'll look at four of the most common design patterns used in the Spring Framework: Singleton pattern. Factory Method pattern. Proxy pattern.
When we begin working with the Spring framework, we run into concepts such as Inversion of Control (IoC), and dependency injection (constructor, setter and field injection) as a way to achieve IoC. Additionally, Spring provides a form of IoC via the service locator pattern.
Below is an example of a service locator class. This returns a service for the given ID from the service registry. The registry is a MAP which is autowired as shown. This is a working example from a production system:
@Service
public class MyServiceLocator {
@Autowired
private Map<String, MyService> myServiceRegistry;
/**
* Service locator to find the right Domain service to interact with the requested data store
*
* @param serviceID
* @return
*/
public MyService locateServiceFor(String serviceID) {
//Using the Given string 'serviceID' as key, lookup the service from the Registry
return myServiceRegistry.get(serviceID);
}
As an option you can use list injection:
public class SomeService {
@Autowired
private List<Parser> parsers;
public doSomethingWithParser(...) {
...
Parser parser = getParser(JsonParser.class);
parser.parse(...);
...
}
private Parser getParser(Class<Parser> targetClass) {
Parser result = null;
for(Parser parser : parsers) {
if(parser.getClass().equals(targetClass)){
result = parser;
}
}
return transformer;
}
}
Even better, you can add Parser.isCompatibleWith(SomeInput input)
method to simplify paser detection code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With