前言:通過前一篇的介紹,我們知道@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,實現自動配置的功能

