Spring boot 编程思想|@Enable 模块驱动

Spring boot 编程思想|@Enable 模块驱动

github示例代码

github对应代码仓库地址:https://github.com/huajiexiewenfeng/spring-cloud-project-learn

1.Spring @Enable 模块驱动

从Spring Framework3.1开始支持@Enable 模块驱动

  • web mvc模块
  • AspectJ代理模块
  • Caching 缓存模块
  • JMX java管理扩展
  • Async 异步处理

引入@Enable 模块驱动的意义:

  • 于能够简化装配步骤
  • 实现了“按需配置”
  • 同时屏蔽组件集合装配的细节

@Enable 模块驱动在 Spring Framework->Spring Boot->Spring Cloud 中的应用

框架实现@Enable 注解模块激活模块
Spring Framework@EnableWebMvcweb mvc 模块
Spring Framework@EnableTransactionManagement事务管理模块
Spring Framework@EnableCaching缓存模块
Spring Framework@EnableMBeanExportJMX模块
Spring Framework@EnableAsync异步处理模块
Spring Framework@EnableWebFluxweb flux模块
Spring Framework@EnableAspectJAutoProxyAspectJ模块
Spring Boot@EnableAutoConfiguration自动装配
Spring Boot@EnableManagementContextactuator模块
Spring Boot@EnableConfigurationProperties配置属性绑定
Spring Boot@EnableOAuth2SsoOAuth2单点登录
Spring Cloud@EnableEurekaServerEureka注册中心
Spring Cloud@EnableConfigServer配置中心
Spring Cloud@EnableFeignClientsfeign客户端
Spring Cloud@EnableZuulProxyzuul网关
Spring Cloud@EnableCircuitBreaker熔断限流

2.@Enable 模块驱动实现

2.1注解驱动

参考

可以参考Spring中的EnableWebMvc的方式

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

DelegatingWebMvcConfiguration

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    ...
}
手动实现
1.新建配置
@Configuration
public class HelloWorldConfiguration {
    @Bean
    public String helloWorld(){
        return "hello world";
    }
}
2.Enable 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}
3.启动类
@EnableHelloWorld
@Configuration
public class EnableHelloWorldBootstrap {
    
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(EnableHelloWorldBootstrap.class);
        //启动上下文
        applicationContext.refresh();
        //获取容器中的bean对象
        String helloWorld = applicationContext.getBean("helloWorld", String.class);
        System.out.println(helloWorld);
        applicationContext.close();

    }

}

执行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0RA5l769-1570696261073)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1570694248388.png)]

2.2接口编程

2.2.1 ImportSelector接口
参考

可以参考 Spring 中的EnableCaching的方式

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {

CachingConfigurationSelector中并没有直接实现ImportSelector#ImportSelector接口

public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
    ...
   @Override
	public String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return getProxyImports();
			case ASPECTJ:
				return getAspectJImports();
			default:
				return null;
		}
	}
    ...
}

但是父类 AdviceModeImportSelector 实现该接口,并重写了selectImports方法

public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
...
	@Override
	public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
		Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
		Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");

		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
		if (attributes == null) {
			throw new IllegalArgumentException(String.format(
				"@%s is not present on importing class '%s' as expected",
				annType.getSimpleName(), importingClassMetadata.getClassName()));
		}

		AdviceMode adviceMode = attributes.getEnum(this.getAdviceModeAttributeName());
		String[] imports = selectImports(adviceMode);
		if (imports == null) {
			throw new IllegalArgumentException(String.format("Unknown AdviceMode: '%s'", adviceMode));
		}
		return imports;
	}
手动实现
1.定义服务器接口Server以及服务器类型:Server.Type
public interface Server {
    //启动服务器
    void start();
    //关闭服务器
    void stop();

    enum Type{
        HTTP,
        FTP
    }
}
2.实现HTTP和FTP服务器
@Component
public class FtpServer implements Server {
    @Override
    public void start() {
        System.out.println("Ftp服务器启动");
    }

    @Override
    public void stop() {
        System.out.println("Ftp服务器关闭");
    }
}

@Component
public class HttpServer implements Server {
    @Override
    public void start() {
        System.out.println("Http服务器启动");
    }

    @Override
    public void stop() {
        System.out.println("Http服务器关闭");
    }
}
3.Enable 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(ServerImportSelector.class)
public @interface EnableServer {
    
    //设置服务器类型
    Server.Type type() default Server.Type.HTTP;
    
}
4.实现ImportSelector接口
public class ServerImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        //读取EnableServer所有的属性方法 本例中的方法为type()
        //key为方法的属性名 value为属性的值
        Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(EnableServer.class.getName());
        //获取注解中设置的值
        Server.Type type = (Server.Type) annotationAttributes.get("type");
        //根据类型选择不同的服务器
        String[] importClassNames = new String[0];
        switch (type) {
            case HTTP:
                importClassNames = new String[]{HttpServer.class.getName()};
                break;
            case FTP:
                importClassNames = new String[]{FtpServer.class.getName()};
                break;
        }
        return importClassNames;
    }

}
5.启动类

设置服务器类型为FTP

@Configuration
@EnableServer(type = Server.Type.FTP)
public class EnableServerBootstrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(EnableServerBootstrap.class);
        //启动上下文
        applicationContext.refresh();
        //获取容器中的bean对象
        Server server = applicationContext.getBean(Server.class);
        server.start();
        server.stop();
        applicationContext.close();
    }
}

执行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrT7cA0L-1570696261074)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1570694182937.png)]

2.2.2 ImportBeanDefinitionRegistrar接口

将上面例子中的ServerImportSelector修改为ImportBeanDefinitionRegistrar接口的实现即可

public class ServerImportDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //复用之前的逻辑
        ImportSelector importSelector = new ServerImportSelector();
        //获取选择的ClassName
        String[] selectedClassNames = importSelector.selectImports(annotationMetadata);
        //创建bean定义
        Stream.of(selectedClassNames)
                //转化为BeanDefinitionBuilder对象
                .map(BeanDefinitionBuilder::genericBeanDefinition)
                //转化为BeanDefinition
                .map(BeanDefinitionBuilder::getBeanDefinition)
                .forEach(beanDefinition -> {
                    //注册到BeanDefinitionRegister
                    BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, beanDefinitionRegistry);
                });
    }
}

3.参考

  • 《Spring Boot 编程思想》-小马哥
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值