spring boot注解方式实现服务切换和服务关闭
- 服务分流,例如在重构一个业务逻辑时,会引流线上一部分数据到重构后的服务,等稳定后在切换至新的服务,如果出现bug可以快速切换至原来的接口
- 高峰期服务降级,例如在我们的业务上有一些统计,在高峰期时这些统计服务就显得不是那么重要,可以在高峰期期间关闭这方面的服务以保证正常业务访问
- 例如在我们的业务场景是服务于所有学校,当一个新的业务上线或者重构原有的业务时我们不希望所有的学校都切换到新的服务接口上来,通过引流一至两所学校到新的服务上做线上测试(灰度发布)。通过spring boot注解并配合disconf动态的关闭服务和切换服务
假设有一个service接口
/** * @author: sylar * @date: 17/12/18 */ public interface SwitchService { String doSwitch(String on); String doSwitch(); String doSwitch(Data data); }
实现类
/** * @author: sylar * @date: 17/12/18 */ @Service(value = "switchServiceAImpl") public class SwitchServiceAImpl implements SwitchService { @Override @OnOffSwitch(switchName = "s0") public String doSwitch(String schoolId) { return on + ":A"; } @Override @OnOffSwitch(switchName = "s1") public String doSwitch() { return "A"; } @Override @OnOffSwitch(switchName = "s2") public String doSwitch(Data data) { return "data:A"; } }
假设业务由于业务bug我们需要动态关闭doSwitch(Data data)的调用防止学校出现安全事故
在disconf上配置如下
nbugs.switch.onoff.rules=[{"on":true,"switchName":"s0"},{"on":true,"switchName":"s1"},{"on":false,"switchName":"s2"}
由于业务的需要我们重构了SwitchServiceAImpl,实现代码如下
/** * @author: sylar * @date: 17/12/18 */ @Service(value = "switchServiceBImpl") public class SwitchServiceBImpl implements SwitchService { @Override public String doSwitch(String schoolId) { return on + ":B"; } @Override public String doSwitch() { return "B"; } @Override public String doSwitch(Data data) { return "data:B"; } }
我们希望学校s001、s002访问serviceA.doSwitch(String schoolId);s003, s004访问serviceB.doSwitch(String schoolId)等等具体配置如下
[ { "beanName": "switchServiceAImpl", "rules": [ { "beanName": "switchServiceAImpl", "paramName": "schoolId", "paramValues": [ "s001", "s002" ] }, { "beanName": "switchServiceBImpl", "paramName": "schoolId", //对应doSwitch(Data data) data的getSchoolId值 "paramValues": [ "s003", "s004" ] } ], "switchName": "s2" }, , { "beanName": "switchServiceAImpl", "rules": [ { "beanName": "switchServiceAImpl", "paramIndex": 0, "paramValues": [ "s001", "s002" ] }, { "beanName": "switchServiceBImpl", "paramIndex": 0, //方法的参数下标,第0个参数值 "paramValues": [ "s003", "s004" ] } ], "switchName": "s0" }, { "beanName": "switchServiceAImpl", //默认调用 serviceA.doSwitch() "switchName": "s1" } ]
因为具体调用serviceA还是serviceB需要在调用时才能确定,所以在注入时@Autowired不能明确指定serviceA还是serviceB需要提供一个代理实现类
/** * @author: sylar * @date: 17/12/18 */ @Service("switchService") public class SwitchServiceImpl implements SwitchService { @Override @ServiceSwitch(switchName = "s0") public String doSwitch(String on) { return null; } @Override @ServiceSwitch(switchName = "s1") public String doSwitch() { return null; } @Override @ServiceSwitch(switchName = "s2") public String doSwitch(Data data) { return null; } }
源码依赖disconf,仅供参考