乐趣区

Springboot基于enable模块驱动

enable 作为模块驱动在 Spring Farmework、Spring Boot、Spring Cloud 使用,都是通过注解的形式以 @enable 作为前缀, 一些常用注解如

框架 注解 模块
Spring Framework @EnableWebMvc Web MVC 模块
Spring Framework @EnableTransactionmanagement Web MVC 模块
Spring Framework @EnableCacheing Cacheing 模块
Spring Framework @EnableMBeanExport JMX 模块
Spring Framework @EnableWebFlux Web Flux 模块
Spring Framework @EnableAspectJAutoProxy AspectJ 模块
Spring Boot @EnableAutoConfiguration 自动装配模块
Spring Boot @EnableWebManagementContext Actuator 模块
Spring Boot @EnableConfigurationProperties 配置属性绑定模块
Spring Boot @EnableOauth2Sso OAuth2 单独登录模块
Spring Cloud @EnableEurekaServer eureka 服务模块
Spring Cloud @EnableConfigServer 配置服务器模块
Spring Cloud @EnableFeignClients Feign 客户端模块
Spring Cloud @EnableZuulProxy 服务网关 zuul 模块
Spring Cloud @EnableCircuitBreaker 服务熔断模块

如何自定义 enable 开发?

基于 ImportSelector 实现注解驱动

自定义接入类型

Access 为接入类型的接口,下文的 RPC 接入和 REST 接入基于这个实现,定义两个接口,一个为启动,一个停止,内部嵌套一个枚举用于标识是哪一种接入

public interface Access {
    /**
     * 初始化配置
     */
    void start();

    /**
     * 销毁配置
     */
    void stop();

    enum Type{
        REST,
        RPC
    }
}

定义 RPC 和 REST 的实现

REST 实现,只是简单的打印方法

public class RestAccess implements Access{
    @Override
    public void start() {System.out.println("rest 接入配置");
    }

    @Override
    public void stop() {System.out.println("rest 接入销毁配置");
    }
}

RPC 实现

public class RpcAccess implements Access{
    @Override
    public void start() {System.out.println("rpc 接入配置");
    }

    @Override
    public void stop() {System.out.println("rpc 接入销毁配置");
    }
}

自定义注解 EnableAccess

接入类型为 RPC 或者 REST,AccessImportSelector 在下一步骤实现

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AccessImportSelector.class)
public @interface EnableAccess {
    /**
     * 接入类型
     * @return
     */
    Access.Type type();}

实现 ImportSelector

定义 AccessImportSelector 实现 ImportSelector,分别获取注解信息,根据注解获取接入类型,根据接入类型选择不同的接入类型

public class AccessImportSelector implements ImportSelector{
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 读取 EnableAccess 中所有的属性方法
        Map<String, Object> annotationAttributes =  annotationMetadata.getAnnotationAttributes(EnableAccess.class.getName());
        // 获取属性为 type 的属性方法
        Access.Type type = (Access.Type)annotationAttributes.get("type");
        // 导入的类名称数组
        String [] importClassName = new String[0];
        switch (type){
            case RPC:
                // 设置为 RPC,返回 RpcAccess 组件
                importClassName = new String[]{RpcAccess.class.getName()};
                break;
            case REST:
                // 设置为 REST,返回 RestAccess 组件
                importClassName = new String[]{RestAccess.class.getName()};
        }
        return importClassName;
    }
}

使用

在 primarySource 也就是这里的 DemoApplication 上使用注解 EnableAccess,选择接入方式,就会初始化不通的接入组件

@SpringBootApplication
@EnableAccess(type=Access.Type.REST)
public class DemoApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Access access = context.getBean(Access.class);
        access.start();
        access.stop();}

}

基于 ImportBeanDefinitionRegistrar 实现注解驱动

这里其它步骤一样,主要区别是注解里面 Import 的类变了,这里是基于基于 ImportBeanDefinitionRegistrar 实现注解驱动实现

自定义 ImportBeanDefinitionRegistrar

public class AccessImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {ImportSelector importSelector = new AccessImportSelector();
        // 筛选 class 名称集合
        String[] selectedClassNames = importSelector.selectImports(annotationMetadata);
        Stream.of(selectedClassNames)
                .map(BeanDefinitionBuilder::genericBeanDefinition)
                .map(BeanDefinitionBuilder::getBeanDefinition)
                .forEach(beanDefinition ->{
                    // 注册 beanDefinition 到 beanDefinitionRegistry
                    BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition,beanDefinitionRegistry);
                });
    }
}

EnableAccess 注解变更

这里 import 导入了 AccessImportBeanDefinitionRegistrar

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AccessImportBeanDefinitionRegistrar.class)
public @interface EnableAccess {
    /**
     * 接入类型
     * @return
     */
    Access.Type type();}

实现

RPC 接入

type=Access.Type.RPC

@SpringBootApplication
@EnableAccess(type=Access.Type.RPC)
public class DemoApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Access access = context.getBean(Access.class);
        access.start();
        access.stop();}

}

REST 接入

type=Access.Type.REST

@SpringBootApplication
@EnableAccess(type=Access.Type.REST)
public class DemoApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Access access = context.getBean(Access.class);
        access.start();
        access.stop();}

}
退出移动版