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,實現自動配置的功能


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM