1、预备知识
1.1 @Import注解和ImportSelector接口
通过@Import注解和配置类实现了ImportSelector接口,可以实现被@Import注解修饰的类导入覆写了ImportSelector接口中selectImports()方法返回的类的全路径名称。
下面举个例子:
package com.jerry.springbootstudy.demo;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* @Description: ImportSelector-demo
* @Author: Jerry
* @Date: 2021-05-13 22:55
*/
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {
User.class.getName(),
Role.class.getName()
};
}
}
该类实现了ImportSelector接口,并复写了selectImports方法,该方法返回要自动装配到Spring容器中的类名称。这里的demo中,返回我们自己定义个User类和Role类的类名。
User:
package com.jerry.springbootstudy.demo;
/**
* @Description: User类
* @Author: Jerry
* @Date: 2021-05-13 22:56
*/
public class User {
}
Role:
package com.jerry.springbootstudy.demo;
/**
* @Description: 角色二类
* @Author: Jerry
* @Date: 2021-05-13 22:56
*/
public class Role {
}
Config配置类:
package com.jerry.springbootstudy.demo;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @Description: 配置类
* @Author: Jerry
* @Date: 2021-05-13 22:58
*/
@Configuration
@Import(MyImportSelector.class)
public class Config {
}
说明:
- 通过@Import注解引入我们上面ImportSelector接口的实现类,将selectImports方法中返回的类名对应的bean装配到Spring容器中;
- 通过@Configuration注解将config类自身装配到Spring容器中。
测试类:
package com.jerry.springbootstudy.demo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
public class ConfigTest {
@Test
public void test() {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
String[] names = context.getBeanDefinitionNames();
Arrays.stream(names).forEach(System.out::println);
}
}
测试类中获取context容器,从容器中获取自动装配到容器中的bean名称并打印,结果如下:
结果可以看出,我们通过ImportSelector接口的实现类的selectImports方法返回的类的bean,成功装配到Spring容器中。
1.2 spring.factories中的EnableAutoConfiguration配置
在很多Spring相关的依赖的META-INF目录下都能看到spring.factories文件,比如在spring-boot-autoconfigure依赖的META-INF目录下就能看到这个文件,如图:
在该文件中的EnableAutoConfiguration配置下,就存放有该依赖中要加载到Spring容器中的bean,还是以spring-boot-autoconfigure的spring.factories为例,如下:
我们看到有rabbitmq相关的配置类,在spring-boot-autoconfigure依赖下果然能找到RabbitAutoConfiguration类,如下:
2、相关源码分析
整体流程如下图所示:
说明:
- 通过在@EnableAutoConfiguration注解里用@Import(EnableAutoConfigurationImportSelector)注解的方式将自动装配的类加载到Spring容器中,哪些类需要加载是由AutoConfigurationImportSelector类里实现额selectImports方法返回;
- 在selectImports方法中,最重要的方法是getCandidateConfigurations方法,该方法里主要是loadFactoryNames方法,该方法读取依赖中META-INF目录下的spring.factories文件,获取spring.factories文件中EnableAutoConfiguration配置下所有要自动装配的类的名称并返回。
3、面试说辞
- 在SpringBoot的启动类上有一个@SpringBootApplication注解,这个注解里有一个@EnableAutoConfiguration注解;
- @EnableAutoConfiguration注解通过@Import导入了一个EnableAutoConfigurationImportSelector类,该类实现了ImportSelector接口,实现了selectImports方法,该方法会返回需要自动装配到Spring容器中的类的名称;
- 再看selectImports方法,该方法只要有三步:
-
- getCandidateConfigurations方法获取所有的bean;
- 获取@SpringBootApplication注解中execlude指定的不需要自动装配的类;
- 返回a中去掉b中的类。
- 主要看getCandidateConfigurations方法,该方法里有一个loadFactoryNames方法,这个方法读取依赖中META-INF目录下的spring.factories文件,获取spring.factories文件中EnableAutoConfiguration配置下所有要自动装配的类的名称并返回。