最近看视频。记一个笔记
1.SpringBoot依赖管理
1.maven中有parent父项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
2. 在spring-boot-starter-parent中有依赖管理
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.4</version>
</parent>
2.自动配置
-
引入依赖
-
配置
自动包配置@AutoConfigurationPackage
在
@SpringBootApplication
中有@EnableAutoConfiguration
和@SpringBootConfiguration
点开@EnableAutoConfiguration之后
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }
有一个@AutoConfigurationPackage 和@Import(AutoConfigurationImportSelector.class),打开@AutoConfigurationPackage
@Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }
导入了一个Registrar类
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); } //BeanDefinitionRegistry Bean注册表 //AnnotationMetadata 注解元数据 这里直接指向你的启动类 因为SpringBootApplication 中有@AutoConfigurationPackage注解 @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); } }
registerBeanDefinitions() 这个方法就是把与启动类同级包里的组件注册进来
AutoConfigurationImportSelector
类public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } /** 这个方法中调用了getAutoConfigurationEntry()方法 得到配置 返回String数组 */
getAutoConfigurationEntry()方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);//getCandidateConfigurations configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } /* getCandidateConfigurations 这个方法中的得到了配置,下面的代码就是做一些操作。然后返回configurations。这些配置是怎么来的呢? */
点开getCandidateConfigurations()
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; } // SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader()); // 利用了SpringFactoriesLoader 利用Spring的工厂加载 loadFactoryNames得到组件
点开loadSpringFactories().
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = cache.get(classLoader); if (result != null) { return result; } result = new HashMap<>(); try { Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue()); for (String factoryImplementationName : factoryImplementationNames) { result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()) .add(factoryImplementationName.trim()); } } } // Replace all lists with unmodifiable lists containing unique elements result.replaceAll((factoryType, implementations) -> implementations.stream().distinct() .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList))); cache.put(classLoader, result); } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } return result; } // Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION); // 这里是加载了一个FACTORIES_RESOURCE_LOCATION的玩意 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
就是加载了spring.factories里的组件 找到这个文件打开后发现有
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 这个玩意
也就是说,这些初始加载的自动配置类是已经在spring.factories里写好了,启动时就自动加载这些类 但是也不是全部加载这些,最后也是按需配置
3.自动配置原理
就是利用@Conditional的派生注解 ConditionalOnBean。。。ConditionalOnMissingBean。。。ConditionalOnClass 虽然是全部加载了,但是也不是全部都能用,需要一些特定的类或者Bean
总结:自动配置原理,就是通过AutoConfigurationImportSelector
中的getAutoConfigurationEntry()方法,在getAutoConfigurationEntry()中通过getCandidateConfigurations()的loadSpringFactories加载已经写好的spring.factories,在spring.factories中导入xxxxAutoConfiguration,在xxxxAutoConfiguration中根据@ConditionalOnProperty
判断是不是要加载这个类里的Bean,通过@EnableConfigurationProperties 注解 开启配置文件类,通过prefix就直接映射到了生成的application.properties来修改配置默认值。