题目
用户有多种支付方式(余额、红包、优惠券,代金券等),假如每种支付方式通过调用远程服务获取可用性。
在外部资源环境不变情况下,请设计程序以最短响应时间获得尽可能多的可用支付方式列表。
假定支付方式可用性咨询接口定义:PaymentRemoteSerivce
接口方法:ConsultResult isEnabled(String paymentType);
返回结果:
public class ConsultResult {
public ConsultResult (boolean isEnable,String errorCode){ this.isEnable = isEnable; this.errorCode= errorCode; } /** 咨询结果是否可用*/ private boolean isEnable; /** 错误码 */ private String errorCode; public boolean getIsEnable(){ return isEnable; } public String getErrorCode(){ return errorCode; } }
解题思路
1、进行远程调用
2、远程调用后存缓存
3、发生变化通过 socket 或者 mq 进行通知,刷新缓存
4、定时刷新缓存、防止某时刻大量请求过来而没得缓存
开干
0、定义支付方式常量
package payWay.other; /** * 支付方式常量 * 余额、红包、优惠券,代金券等 * @author sirwsl */ public class Constants { /** * 余额 */ public static final String BALANCE = "10"; /** * 红包 */ public static final String RED_ENVELOPE = "20"; /** * 优惠券 */ public static final String COUPONS = "30"; /** * 代金券 */ public static final String VOUCHERS = "40"; /** * 其他 */ public static final String OTHER = "50"; }
1、定义支付方式枚举值
package payWay.other; /** * 余额、红包、优惠券,代金券等 * @author sirwsl */ public enum PayWayEnum { //性别枚举 BALANCE("余额", Constants.BALANCE), RED_ENVELOPE("红包", Constants.RED_ENVELOPE), COUPONS("优惠券",Constants.COUPONS), VOUCHERS("代金券",Constants.VOUCHERS), OTHER("其他",Constants.VOUCHERS); private String name; private String value; PayWayEnum(String name, String code) { this.name = name; this.value = code; } public static PayWayEnum matchByValue(String value) { for (PayWayEnum item : PayWayEnum.values()) { if (item.value.equals(value)) { return item; } } return OTHER; } public static PayWayEnum matchByName(String name) { for (PayWayEnum item : PayWayEnum.values()) { if (item.name.equals(name)) { return item; } } return OTHER; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
2、将题目中的返回值封装类诺下来
package payWay.domain; /** * @author sirwsl */ public class ConsultResult { public ConsultResult (boolean isEnable,String errorCode){ this.isEnable = isEnable; this.errorCode= errorCode; } /** 咨询结果是否可用*/ private boolean isEnable; /** 错误码 */ private String errorCode; public boolean getIsEnable(){ return isEnable; } public String getErrorCode(){ return errorCode; } }
3、写远程调用接口
package payWay.service; import payWay.domain.ConsultResult; /** * @author sirwsl */ public interface PaymentRemoteService { ConsultResult isEnabled(String paymentType); }
4、接口实现
package payWay.service.impl; import payWay.domain.ConsultResult; import payWay.other.Constants; import payWay.service.PaymentRemoteService; import java.util.concurrent.TimeUnit; /** * @author sirwsl */ public class PaymentRemoteServiceImpl implements PaymentRemoteService { public static final String SUCCESS = "200"; public static final String SERVER_ERROR = "501"; @Override public ConsultResult isEnabled(String paymentType) { try { Thread.sleep(1000*3); switch (paymentType) { case Constants.BALANCE: case Constants.VOUCHERS: case Constants.RED_ENVELOPE: case Constants.COUPONS: case Constants.OTHER: return new ConsultResult(true, SUCCESS); default: return new ConsultResult(false, SUCCESS); } } catch (InterruptedException e) { return new ConsultResult(false, SERVER_ERROR); } } }
5、模拟缓存
package payWay.other; import java.util.HashMap; import java.util.Map; /** * 模拟缓存操作 * @author sirwsl */ public class CacheMock<T,V> { Map<T,V> cache = new HashMap<>(); public synchronized boolean set(T key,V value){ cache.put(key,value); return true; } public synchronized boolean set(T key,V value,long secconds){ cache.put(key,value); return true; } public V get(T key){ if (cache.containsKey(key)){ return cache.get(key); } return null; } }
6、实现测试、封装获取方式
package payWay; import jdk.nashorn.internal.runtime.logging.Logger; import org.omg.CORBA.BAD_CONTEXT; import payWay.domain.ConsultResult; import payWay.other.CacheMock; import payWay.other.Constants; import payWay.other.PayWayEnum; import payWay.service.PaymentRemoteService; import payWay.service.impl.PaymentRemoteServiceImpl; import sun.rmi.runtime.Log; import javax.management.StringValueExp; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * 业务处理 */ public class Main { static CacheMock<String,ConsultResult> cacheMock = new CacheMock<>(); static PaymentRemoteService paymentRemoteService = new PaymentRemoteServiceImpl(); //测试 public static void main(String[] args) { long start = System.currentTimeMillis(); List<String> test1 = getPayWayList(); System.out.println("================第 1 次时间耗时:"+ (System.currentTimeMillis() - start)+"===============\n结果:"); test1.stream() .map(li -> PayWayEnum.matchByValue(li).getName()) .forEach(li -> System.out.println(li +" ")); start = System.currentTimeMillis(); List<String> test2 = getPayWayList(); System.out.println("================第 2 次时间耗时:"+ (System.currentTimeMillis() - start)+"===============\n结果:"); test2.stream() .map(li -> PayWayEnum.matchByValue(li).getName()) .forEach(li -> System.out.println(li +" ")); start = System.currentTimeMillis(); List<String> test3 = getPayWayList(); System.out.println("================第 3 次时间耗时:"+ (System.currentTimeMillis() - start)+"===============\n结果:"); test3.stream() .map(li -> PayWayEnum.matchByValue(li).getName()) .forEach(li -> System.out.println(li +" ")); } /** * 获取服务排列组合 * @return : 可用支付方式集合 */ public static List<String> getPayWayList(){ //定义收集器 List<String> useWayCollect = new ArrayList<>(Arrays.asList(Constants.BALANCE,Constants.RED_ENVELOPE, Constants.COUPONS,Constants.VOUCHERS,Constants.OTHER)); List<String> canUseWayCollect = new ArrayList<>(4); //多线程从缓存或者远程调用接口 ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5); for(int i = 0; i < useWayCollect.size();i++) { String li = useWayCollect.get(i); Runnable runnable = ()-> { //缓存中拿值 ConsultResult hasUse = cacheMock.get(li); //值为空则远程调用 if (Objects.isNull(hasUse)) { //超时熔断机制,此处不方便搞 hasUse = paymentRemoteService.isEnabled(li); //写缓存 cacheMock.set(li, hasUse); } //去除不能用的 if (hasUse.getIsEnable()) { canUseWayCollect.add(li); } }; executor.execute(runnable); } try { executor.shutdown(); if(!executor.awaitTermination(3000L, TimeUnit.MILLISECONDS)){ executor.shutdownNow(); } }catch (InterruptedException e) { executor.shutdownNow(); Thread.currentThread().interrupt(); } //返回结果 return canUseWayCollect; } }
结束后发现的缺陷
1、没有对 MQ、或者 socket 进行模拟实现
2、模拟缓存、没设置失效时间
3、没有定时任务实时刷新缓存
4、采用原生 java 写,没用 maven 进行管理,有些地方有很大优化
5、由于没有对 mq 进行模拟实现,如果数据变化后,就会造成 fegin 与 cache 数据不一致情况
6、因为说的是远程调用,没有考虑熔断降级的情况
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于