这是我想要实现的简化版本。 我有相同接口的多个实现。根据运行时的用户输入,我想选择正确的实现。
例如,假设我是一个名为Color的接口。有很多类实现了这个接口,Red类,Blue类,Green类等等。
在运行时,我需要根据用户输入选择实现。实现这一目标的一种方法是这样的
@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;
}
}
但问题在于,每次添加新实现时,我都必须更新选择实现的代码,这就是弹簧控制部分反转的全部目的。用弹簧做这件事的正确方法是什么?
答案 0 :(得分:4)
您可以自动装配相关接口的所有实现,然后根据接口提供的属性来决定使用。
@Autowired
private List<Color> colors;
public void doSomething(String input) {
colors.stream().filter(c -> c.getName().contains(input)).findFirst().ifPresent(c -> {
// something
}
}
这也不那么神奇,更符合OO原则。依赖注入最初是为了连接事物,而不是在运行时进行动态切换。
答案 1 :(得分:2)
您希望自动加载ApplicationContext
,然后您可以使用Color
获取所有Map<String, Color> colors = appContext.getBeansOfType(Color.class);
个bean。这假定userInput
和bean名称相同。
如果不是这种情况,解决方案是将getName()
添加到Color
接口;然后你可以自动装配List<Color>
并自己构建地图。
你不能把颜色变成枚举吗?
答案 2 :(得分:1)
Spring ServiceLocatorFactoryBean(向下滚动到中间)API就是为此目的而构建的:
ColorFactory
),提供单一方法,例如Color getColor(String color)
org.springframework.beans.factory.config.ServiceLocatorFactoryBean
创建代理bean实例,将ColorFactory
作为serviceLocatorInterface
参数传递getColor
getColor
你可以在ApplicationContext
上使用类似的API来设计它,但这种方法的优点是它从Java实现中抽象出Spring(对于XML配置的项目)。
答案 3 :(得分:0)
在我的实现中发生了同样的问题,其中场景是基于用户输入的,需要调用相应的接口实现。
这解决了我的问题:
**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);
}
}