zoukankan      html  css  js  c++  java
  • 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,实现自动配置的功能

  • 相关阅读:
    mongo 查询某个字段的值不为空列表!
    pdftohtml的使用
    Activiti数据库表结构(表详细版)
    ElasticSearch在linux上安装部署
    构建Spring Web应用程序—关于spring中的validate注解后台校验的解析
    构建Spring Web应用程序—SpringMVC详解
    高级装配—运行时注入
    高级装配—bean的作用域
    高级装配—条件化的Bean
    高级装配—配置profile bean
  • 原文地址:https://www.cnblogs.com/elnimo/p/13792040.html
Copyright © 2011-2022 走看看