器 | Spring Enable* 一种优雅的实现方式

597 阅读1分钟

一、引言

Spring提供了一系列以Enable开头的注解,这些注解本质上是激活Spring的某些管理功能,比如@EnableCaching,@EnableTransactionManagement。很多文章解析原理都会讲到ImportSelector,以及ImportBeanDefinitionRegistrar,本文不做赘述,本文探讨另一种Enable实现方式。

二、代码实现

假设我们有一个BizCommandsservice接口类,有一个接口#fetchById,有默认的实现。

public interface BizCommands {
    default Optional<String> fetchById(long id){
        return Optional.of("default");
    }
}

根据业务类型的不同我们有不同的实现,暂时具体实现BizCommandsImpl类。

public class BizCommandsImpl implements BizCommands {
    @Override
    public Optional<String> fetchById(long id){
        //todo fetch from external
        final String data = "";
        return Optional.ofNullable(data);
    }
}

在测试环境下我们也许会用接口类里面具体接口的默认实现,但是在预发或者正式环境下我们会用到具体的业务实现。所以需要有一个Enable*去完成这样的切换。

下面是具体实现。

首先添加一个自动配置类,BizCommands接口的默认匿名实现,那么fetchById的具体实现就是default 接口的实现。

@Configuration
public class BizAutoConfigure {
    @Bean
    @ConditionalOnMissingBean
    public BizCommands doctorCommands(){
        return new BizCommands() {};
    }
}

接着添加一个@interface注解EnableDataFromExternal。此注解内部实现了一个配置类,配置类里的BizCommands的实现是具体的业务实现。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({
        EnableDataFromExternal.DataFromExternalConfigure.class
})
public @interface EnableDataFromExternal {
    class DataFromExternalConfigure {
        @Primary
        @Bean
        BizCommands doctorCommands(){
            return new BizCommandsImpl();
        }
    }
}

然后工程目录resources/META-INF下创建文件spring.factories

文件内容为

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
$(your path).BizAutoConfigure

此时开发就已经完成。

然后在项目里面引入此依赖包,在启动类上配置注解EnableDataFromExternal,此时fetchById就是具体的业务实现,取消注解,就是默认的接口实现。