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();}
}