基于运行时条件的Spring开关实现

时间:2016-03-11 00:12:01

标签: java spring

这是我想要实现的简化版本。 我有相同接口的多个实现。根据运行时的用户输入,我想选择正确的实现。

例如,假设我是一个名为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;
}

}

但问题在于,每次添加新实现时,我都必须更新选择实现的代码,这就是弹簧控制部分反转的全部目的。用弹簧做这件事的正确方法是什么?

4 个答案:

答案 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就是为此目的而构建的:

  1. 创建一个虚拟界面(ColorFactory),提供单一方法,例如Color getColor(String color)
  2. org.springframework.beans.factory.config.ServiceLocatorFactoryBean创建代理bean实例,将ColorFactory作为serviceLocatorInterface参数传递
  3. 为所有颜色实现定义bean,其名称与您希望传递给getColor
  4. 的参数相匹配
  5. 将工厂注入协作者并根据需要调用getColor
  6. 你可以在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);
        }

        }