[英]Spring switch implementations based on a runtime condition
This is a simplified version of what I am trying to achieve. 这是我想要实现的简化版本。 I have multiple implementations of the same interface.
我有相同接口的多个实现。 Based on the user input at runtime I want to pick the correct implementation.
根据运行时的用户输入,我想选择正确的实现。
For example suppose I an interface called Color. 例如,假设我是一个名为Color的接口。 There are many classes that implement this interface, the Red class, the Blue class, the Green class and so on.
有许多实现此接口的类,Red类,Blue类,Green类等。
At run time I need to pick implementations based on the user input. 在运行时,我需要根据用户输入选择实现。 One way to achieve this would be something like this
实现这一目标的一种方法是这样的
@Autowired
@Qualifier("Red")
private Color redColor;
@Autowired
@Qualifier("Green")
private Color greenColor;
private Color getColorImplementation()
{
if(userInput=="red")
{
return redColor;
}
else if(userInput=="green")
{
return greenColor;
}
else
{
return null;
}
}
But the problem with this is that everytime a new implementation is added, I would have to update the code that picks the implementation, which beats the whole purpose of inversion of control part of spring. 但问题是,每次添加新实现时,我都必须更新选择实现的代码,这就是弹簧控制部分反转的全部目的。 What is the right way to do this using spring?
用弹簧做这件事的正确方法是什么?
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. 这也不那么神奇,更符合OO原则。 Dependency injection is to wire up things initially, not for dynamic switching at runtime.
依赖注入最初是为了连接事物,而不是在运行时进行动态切换。
You want to Autowire the ApplicationContext
, then you can get all the Color
beans with Map<String, Color> colors = appContext.getBeansOfType(Color.class);
您想要自动装配
ApplicationContext
,然后您可以使用Map<String, Color> colors = appContext.getBeansOfType(Color.class);
获取所有Color
bean Map<String, Color> colors = appContext.getBeansOfType(Color.class);
. 。 This presumes that the
userInput
and the bean name are identical. 这假设
userInput
和bean名称相同。
If that isn't the case, a solution would be to add a getName()
to the Color
interface; 如果不是这种情况,解决方案是将一个
getName()
添加到Color
接口; then you can autowire a List<Color>
and construct the Map yourself. 然后你可以自动装配
List<Color>
并自己构建Map。
Can't you make the Color an Enum? 难道你不能把颜色变成一个枚举?
The Spring ServiceLocatorFactoryBean (scroll down to the middle) API was built just for this purpose: Spring ServiceLocatorFactoryBean (向下滚动到中间)API就是为此目的而构建的:
ColorFactory
) that provides a single method such as Color getColor(String color)
ColorFactory
),提供单个方法,如Color getColor(String color)
org.springframework.beans.factory.config.ServiceLocatorFactoryBean
passing ColorFactory
as the serviceLocatorInterface
parameter org.springframework.beans.factory.config.ServiceLocatorFactoryBean
创建代理bean实例,将ColorFactory
作为serviceLocatorInterface
参数传递 getColor
getColor
的参数相匹配 getColor
as needed getColor
You could contrive this with similar APIs on the ApplicationContext
, but the advantage of this approach is that it abstracts Spring from your Java implementation (for XML configured projects). 您可以在
ApplicationContext
上使用类似的API来设计它,但这种方法的优点是它从Java实现中抽象出Spring(对于XML配置的项目)。
Same issue happen in my implementation where in, the scenario was based on user input, where the respective interface implementation needs to be invoked. 同样的问题发生在我的实现中,其中,场景基于用户输入,其中需要调用相应的接口实现。
This solve my problem: 这解决了我的问题:
**Base Interface**
@Service
public interface ParentInterface {
public String doThis(ClassA param);
}
**First Implementation**
@Component("FirstImp")
public class FirstServiceImp implements ParentInterface {
public String doThis(ClassA param){
}
**Second Implementation**
@Component("SecondImp")
public class SecondServiceImp implements ParentInterface {
public String doThis(ClassA param){
}
**Factory**
@Service
public class ServiceResolver {
@Autowired
@Qualifier("FirstImp")
private ParentInterface firstImpl;
@Autowired
@Qualifier("SecondImp")
private ParentInterface secondImpl;
public ParentInterface getInstance(String condition){
switch(condition) {
case "X": return firstImpl;
case "Y": return secondImpl;
default:
throw new IllegalArgumentException(condition);
}
}
}
**Controller**
@RestController
public class UserController {
@Resource
private ServiceResolver serviceresolver;
@PostMapping("/userbase/{inp1}/messages/{inptype}")
public ResponseEntity<String> sendData(@PathVariable String
inp1,@PathVariable String inptype, @RequestBody XYZBean msg)
{
for(ABC data : msg.getSubData())
serviceresolver.getInstance(data.getType()).doThis(msg);
return new ResponseEntity<String>("created",HttpStatus.OK);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.