SpringBoot学习之自动配置原理
SpringBoot启动时会加载大量自动配置类,大量减少了手动编写配置注入功能组件的工作。
SpringBoot会扫描所有类路径下的META-INF/spring.factories文件,从这获取EnableAutoConfiguration对应的值,这些值就对应了各自自动配置类的路径,将其导入到容器中,就可以进行自动配置了。
接下来看分析源码来熟悉自动配置原理:
1、启动类
@SpringBootApplication public class SpringbootApplication { public static void main(String[] args) { SpringApplication.run(SpringbootApplication.class, args); } }
@SpringBootApplication是一个组合注解
2、@SpringBootApplication
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ...
其中@EnableAutoConfiguration的作用就是启动自动配置
3、@EnableAutoConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ...
通过@Import(AutoConfigurationImportSelector.class)向容器中导入一些组件
4、AutoConfigurationImportSelector.class
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { private static final String[] NO_IMPORTS = {}; private static final Log logger = LogFactory .getLog(AutoConfigurationImportSelector.class); private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude"; private ConfigurableListableBeanFactory beanFactory; private Environment environment; private ClassLoader beanClassLoader; private ResourceLoader resourceLoader; @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); //获取配置名的字符串列表 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return StringUtils.toStringArray(configurations); } ...
List configurations = getCandidateConfigurations(annotationMetadata,
attributes);
作用是扫描并获取类路径下的自动配置类的路径放到字符串列表中
5、getCandidateConfigurations(annotationMetadata,attributes);
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
看注释也能知道该方法作用,主要是List configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());方法
6、SpringFactoriesLoader.loadFactoryNames()
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }
主要是调用loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());方法
7、loadSpringFactories()
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { List<String> factoryClassNames = Arrays.asList( StringUtils.commaDelimitedListToStringArray((String) entry.getValue())); result.addAll((String) entry.getKey(), factoryClassNames); } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
调用Enumeration urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));方法,可以知道,FACTORIES_RESOURCE_LOCATION常量的值为
public abstract class SpringFactoriesLoader { /** * The location to look for factories. * <p>Can be present in multiple JAR files. */ public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; ...
loadSpringFactories方法会扫描所有jar包类路径下 META-INF/spring.factories文件,并把扫描到的这些文件的内容包装成properties对象,然后从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
其他jar包下也类似
- SpringBoot学习_SpringMVC自动配置原理
- SpringBoot学习笔记(3) Spring Boot 运行原理,自动配置
- SpringBoot ——自动配置原理浅析
- Spring Boot核心原理-自动配置
- SpringBoot学习笔记(3) Spring Boot 运行原理,自动配置
- Spring Boot自动配置原理(转)
- Spring Boot核心原理-自动配置
- springboot自动配置的核心原理
- Spring Boot 运行原理之自动配置
- Spring Boot核心原理-自动配置
- SpringBoot学习笔记(5) Spring Boot集成Redis实现自动配置
- springboot自动配置原理
- SpringBoot自动配置原理
- Spring Boot 运行原理 - 查看Spring Boot自动配置项
- SpringBoot学习笔记(四) SpringBoot Web相关的自动配置
- 《Spring Boot 实战:从0到1》第3章 Spring Boot自动配置原理
- springboot学习----自动配置
- Spring Boot自动配置原理、实战
- SpringBoot与数据访问JDBC&自动配置原理(一)
- springBoot 自动配置原理