最近設計一個對外接口調用失敗重試補推功能,由於對於不少接口的調用我準備採起策略模式去實現。思考了下,若是使用普通的策略模式,一個接口對應對個實現類,若是多一個類型的接口,那麼就會多一個實現類,決定使用枚舉策略模式。java
調用接口失敗,將失敗的調用的url,param,method等信息做爲一條記錄存入數據庫中spring
public class HttpFailEntity {
.
.
.
private Integer apiType;
private String url;
private String param;
.
.
.
}
複製代碼
經過定時器從庫中獲取調用外部接口失敗的數據數據庫
List<HttpFailEntity> httpFailEntities;
//補推
httpFailEntities.forEach(httpFailEntity -> {
PushHttpFailEnum.valueOf(httpFailEntity.getApiType()).push(httpFailEntity);
});
複製代碼
使用枚舉策略處理,避免多一個接口處理,新增一個實現類api
public enum PushHttpFailEnum {
/** * id -> 業務接口 */
ONE(1, "A接口") {
private XXXXService xxxxService = SpringContextHolder.getBean(XXXXService.class);
@Override
public Map<String, Object> push(HttpFailEntity httpFailEntity) {
// 補推操做
xxxxService.XXXX();
}
},
TWO(2, "B接口") {
@Override
public Map<String, Object> push(HttpFailEntity httpFailEntity) {
// 補推操做
}
},
.
.
.
OTHER(9999, "") {
@Override
public Map<String, Object> push(HttpFailEntity httpFailEntity) {
return null;
}
};
/** * 補推 * * @param httpFailEntity http推送失敗類 */
public abstract Map<String, Object> push(HttpFailEntity httpFailEntity);
/** * 狀態值 */
@Getter
private int value;
/** * 狀態表述 */
@Getter
private String desc;
PushHttpFailEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
public static PushHttpFailEnum valueOf(int value) {
return Arrays.stream(PushHttpFailEnum.values())
.filter(a -> a.getValue() == value)
.findFirst().orElse(PushHttpFailEnum.ERROR);
}
}
複製代碼
在A接口的實現抽象方法中使用到 spring 容器中的Service類,一開始使用註解形式,運行得時候都是nullapp
@Resource
private XXXXService xxxxService;
複製代碼
後來發現枚舉類裏面實現的抽象方法,本質就是匿名內部類,spring容器根本沒法掃描到,因此也就沒法把對象注入。最後使用SpringContextHolder的靜態方法從spring容器中拿到對應的對象。ide
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
assertApplicationContext();
return applicationContext;
}
public static <T> T getBean(String beanName) {
assertApplicationContext();
return (T) applicationContext.getBean(beanName);
}
public static <T> T getBean(Class<T> requiredType) {
assertApplicationContext();
return applicationContext.getBean(requiredType);
}
private static void assertApplicationContext() {
if (SpringContextHolder.applicationContext == null) {
throw new RuntimeException("ApplicationContext屬性爲null,請檢查是否注入了SpringContextHolder!");
}
}
}
複製代碼