spring boot 使用枚舉策略實戰踩坑

最近設計一個對外接口調用失敗重試補推功能,由於對於不少接口的調用我準備採起策略模式去實現。思考了下,若是使用普通的策略模式,一個接口對應對個實現類,若是多一個類型的接口,那麼就會多一個實現類,決定使用枚舉策略模式。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!");
        }
    }

}
複製代碼
相關文章
相關標籤/搜索