Spring Choose Bean Implementation at Runtime

Spring choose bean implementation at runtime

You can move the bean injection into the configuration, as:

@Configuration
public class AppConfig {

@Bean
public MyService getMyService() {
if(windows) return new MyServiceWin();
else return new MyServiceLnx();
}
}

Alternatively, you may use profiles windows and linux, then annotate your service implementations with the @Profile annotation, like @Profile("linux") or @Profile("windows"), and provide one of this profiles for your application.

Changing the Spring beans implementation at runtime

It doesn't work this way - if you have a certain implementation of Util wired to, say, class SampleClass (which is a singleton) you can't really change the implementation of the Util to something different without restarting the application context.

So instead of going this way, I suggest an alternative. You say that under certain conditions that evaluate in runtime you want to switch implementations. What kind of condition it is? Is it possible to extract this condition decision logic?

If so, you can autowire a special DynamicUtil that will hold the reference to all the utils and will call the required util depending on the condition:

// represents all possible business 'runtime' outcomes
enum ConditionOutcome {
A, B, C
}
interface ConditionEvaluator {
ConditionOutcome evaluate(); // when called in runtime will evaluate a condition that currently exists in the system
}

interface Util {
void foo();
ConditionOutcome relevantOfOutcome();
}

class Utill1Impl implements Util {
public void foo() {...}
public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.A;}
}
class Utill2Impl implements Util {
public void foo() {...}
public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.B;}
}
class Utill3Impl implements Util {
public void foo() {...}
public ConditionOutcome relevantOfOutcome() {return ConditionOutcome.C;}
}

class DynamicUtil {
private final Map<ConditionOutcome, Util> possibleImpls;
private final ConditionEvaluator evaluator;

public class DynamicUtil(List<Util> allImplementations, ConditionEvaluator evaluator) {
// create a map by calling the 'relevantOfOutcome' per util impl in a loop
this.evaluator = evaluator;
}

public void foo() {
ConditionOutcome key = evaluator.evaluate();
// pick the relevant implementation based on evaluated key
possibleImpls.get(key).foo();
}
}

Now with such a design you can dynamically add new possible outcomes (along with utils that should implement them. You classes in the system will have to autowire DynamicUtil though, so effectively you'll introduce one additional level of indirection but will gain flexibility

class SampleClass { // a business class that will need to work with util capable of being changed during the runtime 
@Autowired
private DynamicUtil util;
...
}

How to choose bean implementation at runtime for every http request

I think there is some confusion here about the purpose of the conditions. These aren't being used at the time your requests arrive to autowire the candidate bean into your controller. These are being used when the application is started to configure the application context based on the environment and classpath etc...

There is no need for the conditional classes that you have created. This is defining the configuration of the beans when the context starts and not on a per request basis at runtime.

The use of the static variable is also problematic is a scenario with one or more concurrent requests or in a case where multiple threads may observe different values unless some other mechanism in the java memory model is being used (such as volatile or establishing a happens before relationship, e.g. with sychnronized)

There are a number of ways to do what you appear to be trying to achieve. Since ultimately, you appear to be using a path parameter supplied by a client to determine which service you want to invoke you could use a classic factory pattern to return the correct interface implementation based on the string input programmatically.

Alternatively you could create two distinct controller methods which are distinguished by a query parameter or endpoint name or path match etc. You could then have the appropriate service injected by a qualified bean name

Although perhaps generally recommended, you could also inject an application context instance and search the it looking for the relevant bean by name or class: https://brunozambiazi.wordpress.com/2016/01/16/getting-spring-beans-programmatically/ - although This is more cumbersome and you'd need to handle things like org.springframework.beans.factory.NoSuchBeanDefinitionException or casting in some cases - best avoided in favour of one of the other methods.

Spring choose implementation at runtime from dependencies

Keep it simple : in App2, inject the two DB implementation dependencies (DB impl A and DB impl B) in the bean that needs that and then for each request and according to your "rules", just use the one or the second one.

Now, if in App2, multiple beans need to use both DB implementations, defining a bean that composes them is a better alternative, it would make the code less verbose and duplicated and you could also factor out rules in this aggregator bean.

Spring: how to change interface implementations at runtime

The standard way of doing what you want should be this:

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) {
...
}

}

Currently, however
Spring does not support it (although
it's planned for v5.x). It should work on
application servers.

If you want to stick with Spring, the ServiceLocatorFactoryBean based solution
is probably the best one.

Spring switch implementations based on a runtime condition

You could autowire all implementations of the interface in question and then decide based on properties provided by interface which to use.

@Autowired
private List<Color> colors;

public void doSomething(String input) {
colors.stream().filter(c -> c.getName().contains(input)).findFirst().ifPresent(c -> {
// something
}
}

This is also less magical and more in line with OO principles. Dependency injection is to wire up things initially, not for dynamic switching at runtime.

Decide which of multiple implementations to use in Spring Boot app

Answering my own question.

@Compass and @user268396 were correct - using Profiles got this working as expected.

I created both implementations, annotated with @Service and @Profile("friendly") or @Profile("hostile"), and could change the property spring.profiles.active to dev,friendly for example, and get what I wanted.



Related Topics



Leave a reply



Submit