前言
业务中有个需求,需要跟微信支付和支付宝支付对接,于是想到了,面向接口编程。具体实现就是,定义一个通用接口,微信支付和支付宝支付均实现该接口,这样,在业务代码中,如果需要调用支付方法的话,可以注入这个接口,然后根据类型获取不同的实现类。
具体实现
定义通用接口:
然后不同的支付方式实现该接口,在pay中处理各自的支付逻辑
WxpayService:
AlipayService:
这样,在调用实现类的时候,不需要将每个实现类都注入进去,只需要把接口Payment注入进去,通过一个类型,来确定具体调用哪个实现类,于是我们想到了枚举,根据枚举中的code值拿到对应的实现类,具体实现如下:
这样就可以通过PayType.getByCode()根据类型获取枚举,再拿到枚举中的service实现类:
代码编写完毕,启动项目,发送请求接口:
完犊子!翻车了,哈哈,报空指针了。。。
翻车的原因
既然空指针,我们在报错行打个断点看看:
发现注入的orderService为空,没注入进来。一般发生这种问题是因为,要么是注入的类没有加@Component注解,要么是AliPayService实例化的时候,没有从spring中拿bean。我检查了一下OrderService:
写的有@Component,那毫无疑问,就是第二个原因了。我们回过头来看看AlipayService是怎么实例化的:
发现问题了吧?在枚举中,支付实现类是new出来的,并没有托管给spring。所以在实现类中注入类的话,是拿不到spring托管的类的。
修改解决问题
既然发现了问题,我们就解决一下,枚举中的实现类不是spring容器中的。那么我们要把他们放到容器中或者从容器中拿,那么我们需要在枚举类中定义一个内部类,托管给spring容器,再从内部类中拿实例化好的实现类:
这样枚举中的实现类就是经过spring容器托管后的,之后再在实现类中注入各种类,就不会空指针了。 验证一下:
成功调用orderService中的方法。问题解决!
总结
在spring中,类的托管是非常重要的,我们在使用类时,如果不是从spring的容器中拿到的类,那么这个类中注入的类都会拿不到,这也就是为什么每个类都要交给spring管理的原因。
原文:https://juejin.cn/post/7102622010714357796