Annotation based ServiceLocatorFactoryBean?
Asked Answered
B

2

17

I would like to implement Factory pattern in my project..i have gone through online resources and I came to know that spring ServiceLocatorFactoryBean should be implemented instead of normal java factory pattern....

i have followed this link but it is explained in xml based....can any one tell me how to do it using annotations based Factory pattern??

Banbury answered 30/11, 2015 at 7:2 Comment(0)
C
44

Spring Java Configuration ref guide @Configuration

Interface Parser.class

public interface Parser {
  void parse(String str);
}

Implementation for above interface.

JsonParser.java

public class JsonParser implements Parser {
  @Override
  public void parse(String str) {
     System.out.println("JsonParser.parse::" + str);
  }
}

XMLParser.java

public class XMLParser implements Parser{

  @Override
  public void parse(String str) {
     System.out.println("XMLParser.parse :: " + str);
  }
}

ParserFactory.java actual Factory interface.

public interface ParserFactory {
  public Parser getParser(ParserType parserType);
}

ParseType.java enum to specify parsing types(avoid typos and safe)

public enum ParserType {

JSON("jsonParser"), XML("xmlParser");

private final String value;

  ParserType(String input) {
     this.value = input;
  }

  public String getValue() {
     return this.value;
  }

  @Override
  public String toString() {
    return this.value;
  }
}

ParseService.java , where Business logic implemeted.

@Service
public class ParserService {

 @Autowired
 private ParserFactory parserFactory;

 public void doParse(String parseString, ParserType parseType) {
    Parser parser = parserFactory.getParser(parseType);
    System.out.println("ParserService.doParse.." + parser);
    parser.parse(parseString);
 }
}

Finally AppConfig.java Spring java configuration class, where all of my beans registered as container managed beans.

@Configuration
@ComponentScan(basePackages = {"<Your Package Name>"})
public class AppConfig {
 @Bean
 public FactoryBean serviceLocatorFactoryBean() {
    ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
    factoryBean.setServiceLocatorInterface(ParserFactory.class);
    return factoryBean;
 }

 @Bean(name = "jsonParser")
 @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public JsonParser jsonParser() {
    return new JsonParser();
 }

 @Bean(name = "xmlParser")
 @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public XMLParser xmlParser() {
    return new XMLParser();
 }
}

Now autowire ParserService bean in either controller or test classs, and invoke parese(String, ParseType) method to test.

Here is my test.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class ServiceLocatorFactoryExample {


 @Autowired
 private ParserService parserService;

 @Test
 public void testParserFactory() {
    parserService.doParse("Srilekha", ParserType.JSON);
    parserService.doParse("Srilekha", ParserType.XML);
 }
}
Chloride answered 30/11, 2015 at 7:47 Comment(11)
Thanks a lot @Lovababu. It's working. You made my day.Banbury
I have tried with the example provided by you but I am getting autowiring error on ParseService.java file at ParserFactory line. nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}Banbury
If I remove @Autowired annotation to ParserFactory then i am not getting the above exception but I am getting NullPointerException.Banbury
Do you have ServiceLocatorFactoryBean bean in your configuration?Chloride
yes @Lovababu. You mean similar to that of AppConfig.javaBanbury
I'm curious what if we call non-existing bean, something like parserService.doParse("Srilekha", "NOT EXIST"); what will happen?Plasm
@Lovababu I see you are using scope Prototype here and the Spring docs also seem to suggest this method for prototype. What should be the approach if say the two parsers you have were Singletons?Lass
You can simply remove prototype flag, it should work. If your bean doesn't have any state and if you feel it is thread safe in concurrent programming go with Singleton else prototype.Chloride
I think to prefer return "ServiceLocatorFactoryBean" rather than "FactoryBean" at serviceLocatorFactoryBean() method in AppConfig.java. Because, Static analysis of IntelliJ DEA cannot autowire ParserFactory interface. If you change to ServiceLocatorFactoryBean of return type, that notice will be erase.Interjoin
kumar: I have provided a working code for you. @Please see my post below.Publication
For anyone who wanted to avoid the "raw types" warning message emitted by FactoryBean, don't use FactoryBean. Instead, just return the ServiceLocatorFactoryBean type when creating the ServiceLocatorFactoryBean bean.Logorrhea
N
1

Look this complete example: Serevice Locator factory

It helps me to understand how it works using spring boot.

Nemesis answered 13/9, 2020 at 23:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.