Spring Boot 2.1.1(六)基于ImportSelector接口和@Import注解自定义注解实现Bean装配
前言
上一篇博客讲了@EnableAutoConfiguration注解的工作原理,在上篇博客的基础上自定义注解,实现Bean的装配。
准备工作
在SpringBoot_EnableAutoConfiguration项目中新建两个bean,ImportBean、UserBean。里面啥都没有,什么也不用加,建好就行了。再建个配置类ImportConfiguration。如下:
@Configuration
public class ImportConfiguration {
@Bean
public UserBean userBean() {
return new UserBean();
}
@Bean
public MyRunnable myRunnable() {
return new MyRunnable();
}
}
EnableFlag(装配bean)
创建注解EnableFlag,如下(那些元注解我就不解释了,问度娘)。
/**
* 自定义注解,装配bean
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableFlag {
/**
* bean的完全限定名称
* @return
*/
String[] strName() default {};
/**
* bean的class对象
* @return
*/
Class<?>[] value() default {};
}
上一篇@EnableAutoConfiguration工作原理讲了一个ImportSelector接口,方法返回的是一个Class全路径的String数组,返回的Class会被Spring容器管理。所以注解的实现关键就在这了,创建一个类EnableFlag_ImportSelector实现ImportSelector接口,如下。
EnableFlag_ImportSelector:
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;
import com.eastcom.annotation.EnableFlag;
public class EnableFlag_ImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
System.out.println("=========获取的注解信息>>"+importingClassMetadata.getAnnotationAttributes(EnableFlag.class.getName()));
return StringUtils.toStringArray(getList(importingClassMetadata));
}
private List<String> getList(AnnotationMetadata importingClassMetadata) {
AnnotationAttributes attributes = getAttributes(importingClassMetadata);
List<String> list = getAutoConfigurationList(importingClassMetadata,attributes);
System.out.println("===========返回的list>>"+list);
return list;
}
/**
*
* getAnnotationAttributes(String annotationName,boolean classValuesAsString):检索给定类型的注释的属性
* annotationName:要查找的注释类型的完全限定类名
* classValuesAsString:是否将类引用转换为String类名,以便在返回的Map中将值作为值转换,而不是可能必须首先加载的类引用
*
* fromMap(Map<String,Object>):根据给定的Map返回AnnotationAttributes实例。
* @return
*/
private AnnotationAttributes getAttributes(AnnotationMetadata annotationMetadata){
String name = EnableFlag.class.getName();
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(annotationMetadata.getAnnotationAttributes(name, true));
return attributes;
}
/**
* 获取注解属性值
* @param metadata
* @param attributes
* @return
*/
private List<String> getAutoConfigurationList(AnnotationMetadata metadata,
AnnotationAttributes attributes){
List<String> data = new LinkedList<>();
data.addAll(Arrays.asList(attributes.getStringArray("strName")));
data.addAll(asList(attributes, "value"));
return data;
}
protected final List<String> asList(AnnotationAttributes attributes, String name) {
String[] value = attributes.getStringArray(name);
return Arrays.asList((value != null) ? value : new String[0]);
}
}
我相信看过上篇博客的应该能看懂这个类里的方法都干了些什么。然后用@Import注解导入EnableFlag_ImportSelector,修改EnableFlag注解,如下。
/**
* 自定义注解,装配bean
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableFlag_ImportSelector.class)
public @interface EnableFlag {
/**
* bean的完全限定名称
* @return
*/
String[] strName() default {};
/**
* bean的class对象
* @return
*/
Class<?>[] value() default {};
}
测试运行:
CustomAnnotationApp:
@EnableFlag(value={ImportBean.class},strName="com.eastcom.configuration.ImportConfiguration")
@SpringBootApplication
public class CustomAnnotationApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(CustomAnnotationApp.class, args);
System.out.println(context.getBean(ImportBean.class));
System.out.println(context.getBean("importConfiguration"));
System.out.println(context.getBean(UserBean.class));
}
}
结果:
参数里的ImportBean和ImportConfiguration配置的bean以及ImportConfiguration本身都成功装配。