SpringBoot高级-自动配置之@Import注解

前言:通过前一篇的介绍,我们知道@Enable*底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中,而@Import提供4种用法:

①、导入Bean;
②、导入配置类;
③、导入ImportSelector实现类。一般用于加载配置文件中的类;
④、导入ImportBeanDefinitionRegistrar实现类。

下面我们就这四种用法,一一举例。

一、利用@Import注解导入Bean,测试工程依旧为以前的功能,使用@Import注解,导入User类。

@SpringBootApplication
@Import(User.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);

        Object user = context.getBean("user");
        System.out.println(user);
    }
}

启动程序测试结果:发现找不到user这个Bean,这是因为使用@Import注解,导入User类,给我们创建的bean的名称不是user,所以我们无法通过bean的名称(user)直接获取到bean。

方法一、我们可以通过User的全限定类名,从容器中获取到user这个Bean。

方法二(常用)、通过User类的类型从IOC容器中获取到bean,如下:

@SpringBootApplication
@Import(User.class)
public class SpringbootEnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);

        //一、通过Bean的全限定类名获取Bean
        Object user = context.getBean("com.winson.domain.User");
        System.out.println(user);

        //二、通过Bean的类型获取Bean
        User user1 = context.getBean(User.class);
        System.out.println(user1);

        //getBeansOfType():获取bean的类型
        Map<String, User> map = context.getBeansOfType(User.class);
        System.out.println(map);
    }

}

二、利用@Import注解导入配置类,使用@Import注解,导入UserConfig类。(注:之前讲解Enable*的案例就是利用@Import导入配置类,这里就不再做示例了)

三、利用@Import注解导入ImportSelector实现类

首先新建MyImportSelector类,实现ImportSelector类,重写接口selectImports()方法。之前提到了@Import的这种用法,一般用于加载配置文件中的类,通过selectImports()方法的importingClassMetadata对象,可以获取到注解中的信息,而再由于注解可以获取配置文件中的属性,以此在IOC容器中创建Bean,这里我们就不详细介绍了(注解是@ConditionalOnProperty可以获取配置文件属性)。这里我们再User实体类中又新建了以Role实体类,扩大测试范围。

/**
 * @description:自定义的ImportSelector实现类
 * @date: 2020/10/10 13:10
 * @author: winson
 */
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.winson.domain.User", "com.winson.domain.Role"};
    }
}

修改引导类,使用@Import注解导入自定义的ImportSelector实现类MyImportSelector

@SpringBootApplication
@Import(MyImportSelector.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);

        User user1 = context.getBean(User.class);
        System.out.println(user1);

        Role role = context.getBean(Role.class);
        System.out.println(role);
    }
}

测试结果:

这里再补充一点关于ConfigurableApplicationContext对象的用法,这里我们都是用这个对象获取的bean,但是参数不同,上述是使用User类的类型作为参数,之前我们也用到过参数为user的,这是因为这个对象的getBean有两个重载方法,如下

四、利用@Import注解导入ImportBeanDefinitionRegistrar实现类

首先,新建一个自定义的ImportBeanDefinitionRegistrar接口实现类

/**
 * @description:自定义ImportBeanDefinitionRegistrar的实现类MyImportBeanDefinitionRegistrar,重写接口的registerBeanDefinitions()方法,此方法有两个对象importingClassMetadata、registry,importingClassMetadata对象我们上面的示例已经解释过了,BeanDefinitionRegistry注册器,就是我们可以自定义将bean注册到IOC容器中,BeanDefinitionRegistry有一个registerBeanDefinition()方法,第一个参数:自定义Bean的名称,第二个参数:Bean的定义(Bean的信息),通过BeanDefinitionBuilder对象将User类的Bean信息获取,然后作为参数,就可以自定义Bean到IOC容器中了。
 * @date: 2020/10/10 13:40
 * @author: winson
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //手动注入User的Bean示例
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        registry.registerBeanDefinition("user", beanDefinition);
    }
}

修改引导类

@SpringBootApplication
@Import(MyImportBeanDefinitionRegistrar.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //由于我们自定义了Bean的名称,所以这里我们就可以通过Bean的名称来获取Bean。
        Object user = context.getBean("user");
        System.out.println(user);
    }
}

启动程序,测试结果

小结:最后我们来看看引导类中@SpringBootApplication注解依赖的@EnableAutoConfiguration注解具体的继承关系,可以发现@EnableAutoConfiguration注解也是利用了我们上述第三种方式导入AutoConfigurationImportSelector类

AutoConfigurationImportSelector类的继承关系如下,它实现了DeferredImportSelector接口

DeferredImportSelector接口继承了ImportSelector接口,以此实现导入Bean,实现自动配置的功能

posted @ 2020-10-10 14:08  温森  阅读(772)  评论(0编辑  收藏  举报