本文转载自微信公众号《Java极客技术》,作者鸭血范。转载本文请联系Java极客技术公众号。大家好,我是DuckBlood的粉丝~最近在看同事的代码时学到了一个小技巧,在某些场景下非常有用,在此分享给大家。Spring中的@Autowired注解大家应该都不陌生了。用过Spring的一定也离不开这个注解。这个注解可以帮助我们自动注入我们想要的Bean。除了这个基本功能,@Autowired还有更强大的功能,还可以注入指定类型的数组、List/Set集合,甚至Map对象。比如当前应用有一个支付接口PayService,需要分别连接支付宝、微信支付、银行卡,所以就有了三个不同的实现类AliPayService、WechatPayservice、BankCardPayService。四个类的关系如下图所示:如果此时我需要获取当前系统类的所有PayServiceBeans,那么老办法只能通过BeanFactory或者ApplicationContext来获取。//首先通过getBeanNamesForType;ListanotherPayService=Lists.newArrayList();for(StringbeanName:names){anotherPayService.add(ctx.getBean(beanName,PayService.class));}//或者通过getBeansOfType获取所有PayService类型MapbeansOfType=ctx.getBeansOfType(PayService.class);for(Map.Entryentry:beansOfType.entrySet()){anotherPayService.add(entry.getValue());}但是现在我们不用担心了,我们可以直接使用@Autowired注入PayServiceBean数组,或者PayServiceList/Set集合,甚至,我们也可以注入PayService的Map集合。@AutowiredListpayServices;@AutowiredPayService[]payServicesArray;知道了这个功能,我们需要使用Spring实现策略模式的时候就很简单了。可能有的朋友对策略模型不是很了解,没关系,小编介绍一个业务场景,通过这个场景向大家介绍策略模型。还是上面的例子,我们现在的系统需要对接微信支付、支付宝、银行卡支付。当接到这个需求时,我们首先需要获取对应的接口文档,分析三者的共性。假设我们在这里发现三种模式比较相似,只是有些参数不同。因此,基于三者的共性,我们抽象出一组公共接口PayService,publicinterfacePayService{PayResultepay(PayRequestrequest);},分别实现三个实现类,都继承这个接口。那么现在的问题是,既然有三个实现类,那么具体的实现类该如何选择呢?其实这个问题很容易解决。请求参数传入一个唯一标识,然后我们根据标识选择对应的实现类。比如我们在请求类PayRequest中创建一个channelNo字段,代表对应支付通道的唯一标识。比如支付宝是:00000001,微信支付是00000002,银行卡支付是00000003。那么我们就需要把唯一标识和具体的实现类一一对应起来,就像我们可以用Map来存储这个映射关系。我们实现了一个RouteService,具体代码逻辑如下:}}我们把PayService的所有相关bean都自动注入到RouteService中,然后通过唯一标识找到实现类。这样我们对外屏蔽了支付渠道的差异,其他服务类只需要调用RouteService即可。但是这个实现还是有点问题。由于我们将其唯一标识为一串数字,如果像上面那样直接使用@Autowired注入Map,这就需要我们实现类的Bean名称为00000001。但是这样的命名不是很优雅,会使得后面的学生很难理解和维护。所以我们需要做一个转换,我们可以做到这一点。首先,让我们修改PayService接口并添加一个方法,每个具体实现类通过该方法返回其唯一标识符。publicinterfacePayService{PayResultepay(PayRequestrequest);Stringchannel();}具体拿支付宝实现类的代码,其他实现类类似。@Service("aliPayService")publicclassAliPayServiceimplementsPayService{@OverridepublicPayResultepay(PayRequestrequest){//业务逻辑returnnewPayResult();}@OverridepublicStringchannel(){return"00000001";}}最后我们对RouteService进行改造,具体逻辑如下:@ServicepublicclassRouteService{@AutowiredSetpayServiceSet;MappayServiceMap;publicPayResultepay(PayRequestpayRequest){PayServicepayService=payServiceMap.get(payRequest.getChannelNo());returnpayService.epay(payRequest);}@PostConstructpublicvoidinit(){for(PayServiceSetpayService:pay){payServiceMap=newHashMap<>();payServiceMap.put(payService.channel(),payService);}}}上面的代码首先自动注入了一个PayService的集合,然后我们将其转化为一个Map,这样内部存储的就是唯一标识符和实现类之间的映射。