springboot之ImportSelector解析

发布 : 2019-05-23 分类 : springboot 浏览 :

DeferredImportSelector

介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* A variation of {@link ImportSelector} that runs after all {@code @Configuration} beans
* have been processed. This type of selector can be particularly useful when the selected
* imports are {@code @Conditional}.
*
* <p>Implementations can also extend the {@link org.springframework.core.Ordered}
* interface or use the {@link org.springframework.core.annotation.Order} annotation to
* indicate a precedence against other {@link DeferredImportSelector}s.
*
* <p>Implementations may also provide an {@link #getImportGroup() import group} which
* can provide additional sorting and filtering logic across different selectors.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 4.0
*/
  • 他是ImportSelector的一个扩展实现。基本是在所有的Configuration中所有bean实例化完成后,才会触发。在Import的类是Conditional的时候,这个类型的Selector特别有用。
  • 主要实现方法是selectImports,返回对应的全类名。

使用

  • 定义三个Configuration。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    @Slf4j
    public class MyConfiguration1 {
    public MyConfiguration1() {
    log.info("MyConfiguration1 construct...");
    }

    public void execute() {
    log.info("MyConfiguration1 execute...");
    }
    }

    @Slf4j
    public class MyConfiguration2 {
    public MyConfiguration2() {
    log.info("MyConfiguration2 construct...");
    }

    public void execute() {
    log.info("MyConfiguration2 execute...");
    }
    }

    @Slf4j
    public class MyConfiguration3 {
    public MyConfiguration3() {
    log.info("MyConfiguration3 construct...");
    }

    public void execute() {
    log.info("MyConfiguration3 execute...");
    }
    }
  • 定一个导入类

    1
    2
    3
    4
    5
    6
    public class MyImportSelector implements DeferredImportSelector {
    @Override public String[] selectImports(AnnotationMetadata annotationMetadata) {
    return new String[]{MyConfiguration1.class.getName(), MyConfiguration2.class.getName(),
    MyConfiguration3.class.getName()};
    }
    }
  • 定一个Configuration进行Import

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Slf4j
    @Configuration
    @Import(MyImportSelector.class)
    public class MyConfiguration {
    @Bean
    public Object test() {
    log.info("MyConfiguration create a object bean...");
    return new Object();
    }
    }
  • 启动类

    1
    2
    3
    4
    5
    6
    @SpringBootApplication
    public class App {
    public static void main(String[] args) {
    SpringApplication.run(App.class,args);
    }
    }
  • 查看启动日志

    可以看到,在Configuration类中的bean实例化后,才执行Import。

ImportSelector

介绍

1
2
3
4
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/

基本就是返回需要被Import到容器中的class。

使用

1
2
3
4
5
6
public class MyImportSelector implements ImportSelector {
@Override public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{MyConfiguration1.class.getName(), MyConfiguration2.class.getName(),
MyConfiguration3.class.getName()};
}
}
  • 看下启动日志

    和Deferred的区别就是他是先Import的。

AnnotationMetadata这个类

这个比较实用。记得之前写过一个分布式任务调度的框架,如果结合springboot,那么在做一些自定义配置的时候就好很多。如:

  • 定义一个注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import(MyHttpDeferredImportSelector.class)
    public @interface MyHttp {
    String name() default "";
    String value() default "";

    }
  • 注解实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Slf4j
    public class MyHttpDeferredImportSelector implements DeferredImportSelector {
    @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    importingClassMetadata.getAllAnnotationAttributes(MyHttp.class.getName(),true)
    .forEach((k,v) -> {
    log.info(importingClassMetadata.getClassName());
    log.info("k:{},v:{}",k,String.valueOf(v));
    });
    return new String[0];
    }
    }
  • 使用注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Slf4j
    @MyHttp(name = "myc1",value = "myc1-value")
    public class MyConfiguration1 {
    public MyConfiguration1() {
    log.info("MyConfiguration1 construct...");
    }

    public void execute() {
    log.info("MyConfiguration1 execute...");
    }
    }

我们运行的时候能看到如下结果:

我们能取到使用注解类的所有信息。这样子,在自定义一些处理规则的时候,会方便很多。

总结

ImportSelector这个springboot的钩子,一般配合Import注解使用,功能还是比较强大的。在自定义一些注解的时候,比较好用。

本文作者 : braveheart
原文链接 : https://zhangjun075.github.io/passages/springboot-ImportSelector/
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

知识 & 情怀 | 二者兼得

微信扫一扫, 向我打赏

微信扫一扫, 向我打赏

支付宝扫一扫, 向我打赏

支付宝扫一扫, 向我打赏

留下足迹