DeferredImportSelector
介绍
/**
* 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。
@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...");
}
}
- 定一个导入类
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
@Slf4j
@Configuration
@Import(MyImportSelector.class)
public class MyConfiguration {
@Bean
public Object test() {
log.info("MyConfiguration create a object bean...");
return new Object();
}
}
- 启动类
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
可以看到,在Configuration类中的bean实例化后,才执行Import。
ImportSelector
介绍
/**
* 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。
使用
public class MyImportSelector implements ImportSelector {
@Override public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{MyConfiguration1.class.getName(), MyConfiguration2.class.getName(),
MyConfiguration3.class.getName()};
}
}
-
看下启动日志
imps1.png
和Deferred的区别就是他是先Import的。
AnnotationMetadata这个类
这个比较实用。记得之前写过一个分布式任务调度的框架,如果结合springboot,那么在做一些自定义配置的时候就好很多。如:
- 定义一个注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(MyHttpDeferredImportSelector.class)
public @interface MyHttp {
String name() default "";
String value() default "";
}
- 注解实现类
@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];
}
}
- 使用注解
@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注解使用,功能还是比较强大的。在自定义一些注解的时候,比较好用。
网友评论