Spring @Enable 模块驱动原理

说明

Spring或Spring Boot中我们经常会用到很多@EnableXXX 注解,加上这些注解之后我们就可以 ‘启用’ 某一个功能,或者可以使用某些Bean,比如:

@EnableAsync 使用异步执行、

@EnableTransactionManagement 启用事务、

@EnableAutoConfiguration 开启自动装配

等等,那么你知道背后的原理是什么样的吗?本文简要窥探一下。

原理

无论是Spring内建的,还是我们自定义的@Enable 模块,基本就3种实现方式,其目标都是将指定的类定位为Spring Bean:

  1. 导入类为@Configuration Class。
  2. 导入类为 ImportSelector实现;
  3. 导入类为 ImportBeanDefinitionRegistrar实现;

实例1:

引导类为 @Configuration ,声明Enable注解

<code>@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloworldConfiguration.class)
public @interface EnableHelloWorld {
}/<code>

@Configuration Class中定义Bean

@Configuration

public class HelloworldConfiguration {

@Bean

public String helloWorld() {

return "Hello, world";

}

}

开启EnableHelloWorld注解,获取 helloWorld Bean

<code>@Configuration@EnableHelloWorldpublic class EnableHelloWorldBootstrap {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();       
      // 注册当前引导类(被@Configuration标注)到Spring上下文        
      context.register(EnableHelloWorldBootstrap.class);        
      // 启动上下文        
      context.refresh();        
      // 获取Bean        
      String helloWorld = context.getBean("helloWorld", String.class);       
      System.out.printf("helloWorld = %s \n", helloWorld);        
      // 关闭上下文        
      context.close();   
    }
}/<code>

执行结果:

helloWorld = Hello, world

实例2:导入类为 ImportSelector实现

<code>public interface Server {

    void start();    
   void close();    
   enum ServerType {        HTTP,        TCP    }
}/<code>
<code>@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServerImportSelector.class)
public @interface EnableServer {
    Server.ServerType type();
} /<code>

根据注解属性,选择要定义的Bean

<code>public class ServerImportSelector implements ImportSelector {
    @Override    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        Map attributes = annotationMetadata.getAnnotationAttributes(EnableServer.class.getName());        
        Server.ServerType serverType = (Server.ServerType)attributes.get("type");        
        String[] importClassNames = new String[0];        
        switch (serverType) {            
          case HTTP:                
            importClassNames = new String[]{HttpServer.class.getName()};                
            break;            
          case TCP:                
            importClassNames = new String[]{TcpServer.class.getName()};               
            break;       
        }
        return importClassNames;    
    }
}/<code>

启用Server,获取对应的功能:

<code>@Configuration
@EnableServer(type = Server.ServerType.TCP)
public class EnableServerBootsrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();       
        context.register(EnableServerBootsrap.class);        
        context.refresh();      
        // 获取Bean
        Server server = context.getBean(Server.class);       
        // 启用功能
        server.start();        
        server.close();        
        context.close();    
    }
}/<code>

执行结果:

TcpServer start ...

TcpServer close ....

实例3:

导入类为 ImportBeanDefinitionRegistrar实现

<code>@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServerImportBeanDefinitionRegistrar.class)
public @interface EnableServer {
    Server.ServerType type();
}/<code>

注册Bean

<code>public class ServerImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
          ImportSelector importSelector = new ServerImportSelector();        // 筛选Class名称集合        String[] selectedClassNames = importSelector.selectImports(importingClassMetadata);        // 创建Bean定义        Stream.of(selectedClassNames)
                // 转化为BeanDefinitionBuilder对象                .map(BeanDefinitionBuilder::genericBeanDefinition)
                // 转化为BeanDefinition                .map(BeanDefinitionBuilder::getBeanDefinition)
                .forEach(beanDefinition -> {
                    // 注册BeanDefinition到BeanDefinitionRegistry                    BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);                });    }
}/<code>

启用Server,获取对应的功能:见实例2。

内建模块

Spring 内建模块

<code>@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
}/<code>

Dubbo 内建模块

<code>@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
}/<code>

具体实现可以看下源码,都是相同的原理。


分享到:


相關文章: