【SpringBoot】Re 02 Import与自定义装配实现

Import的注册形式:

1、使用@Import导入一个或者多个类字节对象

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    Class<?>[] value();
}

使用时一般在配置类上注解,表示该注解类导入了其他配置

@Configuration
@Import({
        MyBeanFactoryPostProcessor.class,
        ClassA.class,
        ClassB.class,
        ClassC.class
})
public class TestConfiguration {
}

2、使用导入Bean定义登记者

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(ClassD.class);
        registry.registerBeanDefinition("classD", rootBeanDefinition);
    }
}

然后配置导入:

@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class TestConfiguration {
}

测试运行:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
public class DefinitionTest {
    @Autowired
    private ClassD classD;

    @Test
    public void testSample() {
        System.out.println(classD);
    }
}
cn.dzz.bean.ClassD@6771beb3

Process finished with exit code 0

3、使用【导入选择器】

原始版本是直接声明类完整路径名

public class MyImportSelector implements ImportSelector {

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[] {"cn.dzz.bean.ClassD"};
    }
}

导入配置:

@Configuration
@Import(MyImportSelector.class)
public class TestConfiguration {
}

测试结果:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
public class DefinitionTest {
    @Autowired
    private ClassD classD;

    @Test
    public void testSample() {
        System.out.println(classD);
    }
}
cn.dzz.bean.ClassD@682b2fa

Process finished with exit code 0

第二版本,类的限定名固定编写在源码文件中不可灵活改变:

我们可以通过外部的配置文件来实现:

1、创建配置读取类

public class Tc51AutoConfigReader {

    public static Properties readerProperties(String resource){
        Properties properties = new Properties();
        InputStream it = Tc51AutoConfigReader.class.getResourceAsStream(resource);

        try {
            properties.load(it);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return  properties;
    }
}

2、获取字符串,但是这个方法写的非常简单,只读取了一个类

我们的一个Map是允许一个键存储多个值的,也就是读取多个类

public String[] selectImports(AnnotationMetadata annotationMetadata) {
  Properties properties = Tc51AutoConfigReader.readerProperties("/Tc51autoconfig.properties");
  String property = properties.getProperty(Tc51EnableAutoConfig.class.getName());
  return new String[]{property};
}

第三版本,调用Spring写好的方法和注解方式实现自动装配
首先仿照SpringBoot创建这样的配置文件:

内部配置信息:

cn.dzz.annotation.MyEnableAutoConfiguration = \
  cn.dzz.config.RedisConfiguration

声明一个自定义开启自动配置注解:

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

然后实现导入选择器接口的方法变成这样:

public class MyImportSelector implements ImportSelector {

    private Class<?> getMyFactoryLoaderClass(){
        return MyEnableAutoConfiguration.class;
    }

    private List<String> getConfiguration(){
        return SpringFactoriesLoader.loadFactoryNames(
            getMyFactoryLoaderClass(),MyImportSelector.class.getClassLoader()
        );
    }

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return StringUtils.toStringArray(getConfiguration());
    }
}

首先是得到注解类的字节对象,它被下面的方法所需要,

获取配置方法可以从配置文件中读取信息返回一个List集合,里面装载了那些类限定名(配置信息)

需要的参数是上面写的注解类字节对象和一个类加载器

再返回给选择器方法,集合转换一下数组即可

 

posted @ 2020-08-18 22:52  emdzz  阅读(282)  评论(0编辑  收藏  举报