【问题标题】:Spring switch implementations based on a runtime condition基于运行时条件的 Spring switch 实现
【发布时间】:2016-03-11 00:12:00
【问题描述】:

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

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

}

但问题在于,每次添加新实现时,我都必须更新选择实现的代码,这超出了 spring 控制部分反转的整个目的。使用弹簧执行此操作的正确方法是什么?

【问题讨论】:

    标签: java spring


    【解决方案1】:

    您可以自动装配相关接口的所有实现,然后根据接口提供的属性决定要使用的接口。

    @Autowired
    private List<Color> colors;
    
    public void doSomething(String input) {
        colors.stream().filter(c -> c.getName().contains(input)).findFirst().ifPresent(c -> {
            // something
        }
    }
    

    这也没有那么神奇,更符合 OO 原则。依赖注入最初是为了连接事物,而不是在运行时动态切换。

    【讨论】:

    • 非常好的解决方案。如果您声明Map&lt;String, Color&gt; colors 而不是List,您甚至可以改进它。然后,应使用@Component("colorName") 声明新颜色。在这种情况下,您甚至可以为一种颜色创建多个同义词,而无需让 Color 类知道任何关于颜色分辨率的事情。
    • @Ken:我认为您的评论应该是答案的一部分。我最终确实按照您建议的方式使用了地图,然后通过 @Component("BeanName") 中声明的名称从地图中获取项目。完美运行!
    • @developer747 我很高兴能提供帮助。主要思想 - zapl 建议的根据基本类型自动生成 bean 列表。其他只是细节。
    • @Ken:我的意思是说我已经实现了它。我使用了你和 zapl 的建议。我认为如果可以修改答案以包含您的评论,那将对我们未来的读者有益。
    【解决方案2】:

    您想自动装配ApplicationContext,然后您可以使用Map&lt;String, Color&gt; colors = appContext.getBeansOfType(Color.class); 获取所有Color bean。这假定userInput 和bean 名称相同。

    如果不是这样,一个解决方案是在Color 接口中添加一个getName();然后你可以自动装配一个List&lt;Color&gt; 并自己构建地图。

    你不能把颜色设为枚举吗?

    【讨论】:

    • 这是可以接受的做法吗?调用 appContext 获取 bean?但这听起来是个好主意。我可能会同意。
    • AppContext 已经存在并且可以自动装配,所以不需要额外的努力。请记住,您只需要在 bean 的构造函数中或在它的 @PostConstruct 中执行此操作。
    【解决方案3】:

    Spring ServiceLocatorFactoryBean(向下滚动到中间)API 就是为此目的而构建的:

    1. 创建一个虚拟接口 (ColorFactory),提供单一方法,例如 Color getColor(String color)
    2. org.springframework.beans.factory.config.ServiceLocatorFactoryBean 创建代理bean 实例,将ColorFactory 作为serviceLocatorInterface 参数传递
    3. 为您的所有颜色实现定义bean,其名称与您要传递给getColor的参数匹配
    4. 将工厂注入协作者并根据需要调用getColor

    您可以在 ApplicationContext 上使用类似的 API 来实现这一点,但这种方法的优点是它从您的 Java 实现中抽象出 Spring(对于 XML 配置的项目)。

    【讨论】:

    【解决方案4】:

    同样的问题发生在我的实现中,该场景基于用户输入,需要调用相应的接口实现。

    这解决了我的问题:

            **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);
            }
    
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 2015-03-25
      • 2020-08-05
      相关资源
      最近更新 更多