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!");
        }
    }

}
复制代码
相关文章
相关标签/搜索