Spring: how to change runtime interface implementations

As a Java developer, I often have to choose between different implementations of my interfaces. Sometimes this choice can be made once, and in some other cases I need different implementations in response to the different inputs that my program receives. In other words, I need to be able to change the implementation at runtime. This is easily achieved with a helper object that converts some key (based on user input) into a link to a suitable interface implementation.

With Spring, I can create an object like a bean and embed it wherever I need:

public class MyClass {

    @Autowired
    private MyHelper helper;

    public void someMethod(String someKey) {
        AnInterface i = helper.giveMeTheRightImplementation(someKey);
        i.doYourjob();
    }

}

Now, how do I implement an assistant? Let's start with this:

@Service
public class MyHelper {

    public AnInterface giveMeTheRightImplementation(String key) {
        if (key.equals("foo")) return new Foo();
        else if (key.equals("bar")) return new Bar();
        else ...
    }

}

. , , , , , . , Foo :

@Service
public class Foo {

    @Autowired
    private VeryCoolService coolService;

    ...

}

... Foo, MyHelper, coolService.

, :

@Service
public class MyHelper {

    @Autowired
    private Foo foo;

    @Autowired
    private Bar bar;

    ...

    public AnInterface giveMeTheRightImplementation(String key) {
        if (key.equals("foo")) return foo;
        else if (key.equals("bar")) return bar;
        else ...
    }

}

. - :

@Service
public class MyHelper {

    @Autowired
    private ApplicationContext app;

    public AnInterface giveMeTheRightImplementation(String key) {
        return (AnInterface) app.getBean(key);
    }

}

Spring ApplicationContext.

ServiceLocatorFactoryBean:

public interface MyHelper {

    AnInterface giveMeTheRightImplementation(String key);

}

// Somewhere else, in Java config

@Bean
ServiceLocatorFactoryBean myHelper() {
    ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
    bean.setServiceLocatorInterface(MyHelper.class);
    return bean;
}

Spring, , .

+4
3

, , :

interface YourInterface {
    void doSomething();
}

public class YourClass {

    @Inject @Any Instance<YourInterface> anImplementation;

    public void yourMethod(String someInput) {
        Annotation qualifier = turnInputIntoQualifier(someInput);
        anImplementation.select(qualifier).get().doSomething();
    }

    private Annotation turnInputIntoQualifier(String input) {
        ...
    }

}

, , Spring ( v5.x). .

Spring, ServiceLocatorFactoryBean , .

+2

. , .

-

enum Mapper{
    KEY1("key1", "foo"),
    KEY2("key2", "bar")
    ;

    private String key;
    private String beanName;

    public static getBeanNameForKey(String key){
       // traverse through enums using values() and return beanName for key
    }
}

, Foo Bar Comman. AnInterface

class ImplFactory{

    @Autowired
    Map<String, AnInterface> implMap; // This will autowire all the implementations of AnInterface with the bean name as the key

    public AnInterface getImpl(string beanName){
            implMap.get(beanName);
    }
  }

@Service
public class MyHelper {

@Autowired
ImplFactory factory;

    public AnInterface giveMeTheRightImplementation(String key) {

        String beanName = Mapper.getBeanNameForKey(key);  
        factory.getImpl(beanName);
    }  
}

,
 1. , , .
 2. . , , Mapper enum ( Impl).
 3. Bean , ( Bean, spring). factory. .

EDIT:   beans, value . . Impl @Component @Service, @Component("myBeanName1") @Service("myBeanName2")

+3

beans, , bean . , bean, , , . spring.

@Service
public class MyHelper {
   @Autowired
   ApplicationContext applicationContext;

   public AnInterface giveMeTheRightImplementation(String key) {

   return context.getBean(key);
}

}

@Service("foo")
public class Foo implements AnInterface {
}
0

Source: https://habr.com/ru/post/1677249/


All Articles