网站群建设的必要性,北京网站建设公司拟,国企网站建设标准,做标签的网站文章目录 1. SpringBoot的自动配置概念2. SpringBoot自动配置的原理3. EnableAutoConfiguration4. 常用的Conditional注解 1. SpringBoot的自动配置概念
SpringBoot相对于SSM来说#xff0c;主要的优点就是简化了配置#xff0c;不再需要像SSM哪有写一堆的XML配置#xff0… 文章目录 1. SpringBoot的自动配置概念2. SpringBoot自动配置的原理3. EnableAutoConfiguration4. 常用的Conditional注解 1. SpringBoot的自动配置概念
SpringBoot相对于SSM来说主要的优点就是简化了配置不再需要像SSM哪有写一堆的XML配置这些XML配置在大项目上会成为一种累赘使得后期项目难以维护。
SpringBoot的出现使得开发者不再关注于配置能够更加专注于业务的开发这得益于SpringBoot的自动配置。 2. SpringBoot自动配置的原理
SpringBoot的自动配置的核心就在于SpringBoot启动类中的SpringBootApplication注解上
SpringBootApplication
Slf4j
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);log.info(Project running .....);}}这是一个复合注解标识该类为SpringBoot的应用入口里面包含了SpringBootConfiguration、EnableAutoConfiguration、ComponentScan三个注解
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 {....
}三个注解的作用如下
SpringBootConfiguration这是SpringBoot框架中的一个特殊注解属于Configuration派生注解它的作用是在应用启动时会被自动加载和处理简化应用程序的配置过程提供快速的启动配置.EnableAutoConfiguration启用自动配置机制自动配置的核心ComponentScan扫描启动类路径下的类自动注册带有Component以及其他相关注解的类到Spring容器中 3. EnableAutoConfiguration
EnableAutoConfiguration翻译过来就是开启自动配置说明这个类的作用就是开启自动配置的作用。
Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Inherited
AutoConfigurationPackage
Import({AutoConfigurationImportSelector.class})
public interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY spring.boot.enableautoconfiguration;Class?[] exclude() default {};String[] excludeName() default {};
}EnableAutoConfiguration也是一个复合注解其中AutoConfigurationPackage注解的作用是将当前类所在的包以及子包作为自动配置的包路径以便让SpringBoot能够自动加载和处理这些组件的配置。
Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Inherited
Import({AutoConfigurationPackages.Registrar.class})
public interface AutoConfigurationPackage {String[] basePackages() default {};Class?[] basePackageClasses() default {};
}AutoConfigurationPackage中有Import({AutoConfigurationPackages.Registrar.class})
Import({AutoConfigurationPackages.Registrar.class})的作用是导入一个配置文件在springboot中为给容器导入一个组件而导入的组件由 AutoConfigurationPackages.class的内部类Registrar.class 执行逻辑来决定是如何导入的。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {Registrar() {}public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));}public SetObject determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImports(metadata));}
}Registrar作为一个静态内部类实现了ImportBeanDefinitionRegistrar接口就可以被Import注入到Spring容器中。
在这里类中需要重点关注registerBeanDefinitions方法 通过DEBUG发现(String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0])的值为当前启动类所在的包名。
因此可以得出结论这个方法的主要作用是启动类所在的包下的所有组件注入到Spring容器中。
接着再看Import({AutoConfigurationImportSelector.class})
通过Import将AutoConfigurationImportSelector选择器导入。
在AutoConfigurationImportSelector需要重点关注getAutoConfigurationEntry方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {// 检查是否开始自动配置如果返回false则不开启不需要导入任何配置类return EMPTY_ENTRY;} else {//从注解元数据中获取自动配置相关属性AnnotationAttributes attributes this.getAttributes(annotationMetadata);//根据注解元数据和属性获取潜在的候选自动配置类的列表ListString configurations this.getCandidateConfigurations(annotationMetadata, attributes);//去除重复的自动配置类configurations this.removeDuplicates(configurations);//获取与自动配置相关的排除列表即需要从候选自动配置中排除的类。SetString exclusions this.getExclusions(annotationMetadata, attributes);//检查排除列表中的类是否存在于候选自动配置列表中并进行必要的处理。this.checkExcludedClasses(configurations, exclusions);//从候选自动配置列表中移除在排除列表中指定的类。configurations.removeAll(exclusions);//使用配置类过滤器ConfigurationClassFilter对候选自动配置列表进行进一步筛选和过滤。configurations this.getConfigurationClassFilter().filter(configurations);//触发自动配置导入事件可以通知其他监听器关于自动配置的导入信息。this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}
}这个方法的返回值是候选的配置类经过处理和筛选后的自动配置类列表以及排除列表。
重点是关注如何获取自动配置类列表这个需要关注getCandidateConfigurations方法
protected ListString getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {//使用 SpringFactoriesLoader 从 META-INF/spring.factories 文件中加载所有的工厂名称并将它们存储在一个新的 ArrayList 中。//getSpringFactoriesLoaderFactoryClass() 返回用于加载自动配置的工厂类。ListString configurations new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));//使用 ImportCandidates 从指定的类路径加载 AutoConfiguration 类的子类或实现类并将它们添加到候选配置列表中。//this.getBeanClassLoader() 返回当前线程的类加载器。ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations, No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.);return configurations;
}这个方法的主要作用就是利用SpringFactoriesLoader加载META-INF/spring.factories文件
public static ListString loadFactoryNames(Class? factoryType, Nullable ClassLoader classLoader) {//配置类加载器ClassLoader classLoaderToUse classLoader;if (classLoader null) {classLoaderToUse SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName factoryType.getName();return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}接着查看loadSpringFactories这里面就是获取需要配置的类的主要核心过程了。
private static MapString, ListString loadSpringFactories(ClassLoader classLoader) {//首先从缓存中获取给定类加载器classLoader对应的工厂配置信息。如果缓存中已存在则直接返回结果。MapString, ListString result (Map)cache.get(classLoader);if (result ! null) {return result;} else {//用于存储工厂配置信息。MapString, ListString result new HashMap();try {//使用给定的类加载器获取所有位于 META-INF/spring.factories 路径下的资源文件的 URL 枚举EnumerationURL urls classLoader.getResources(META-INF/spring.factories);//遍历每个资源文件的 URLwhile(urls.hasMoreElements()) {//获取下一个资源文件的 URLURL url (URL)urls.nextElement();//将 URL 封装为 UrlResource 对象以便进行读取。UrlResource resource new UrlResource(url);//通过 PropertiesLoaderUtils 加载 UrlResource 对象所代表的资源文件并将其作为属性对象 Properties 进行读取。Properties properties PropertiesLoaderUtils.loadProperties(resource);Iterator var6 properties.entrySet().iterator();//遍历每个属性条目。while(var6.hasNext()) {Map.Entry?, ? entry (Map.Entry)var6.next();//提取工厂类型名称并进行去除首尾空格的处理。String factoryTypeName ((String)entry.getKey()).trim();//将工厂实现类名按逗号分隔转换为字符串数组。String[] factoryImplementationNames StringUtils.commaDelimitedListToStringArray((String)entry.getValue());String[] var10 factoryImplementationNames;int var11 factoryImplementationNames.length;for(int var12 0; var12 var11; var12) {String factoryImplementationName var10[var12];//将工厂实现类名添加到对应的工厂类型键下的列表中。如果该键不存在则创建一个新的空列表。((List)result.computeIfAbsent(factoryTypeName, (key) - {return new ArrayList();})).add(factoryImplementationName.trim());}}}//对结果中的每个工厂类型及其对应的实现类列表进行去重操作并将列表转换为不可修改的集合以确保唯一性result.replaceAll((factoryType, implementations) - {return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));});//将结果存储到缓存中以便下次直接获取cache.put(classLoader, result);return result;} catch (IOException var14) {throw new IllegalArgumentException(Unable to load factories from location [META-INF/spring.factories], var14);}}
}也就是说这个方法通过加载和解析 META-INF/spring.factories 文件中的内容将工厂类型和其对应的实现类名关联起来并返回一个包含工厂配置信息的 Map 对象。它使用了缓存机制来避免重复加载相同的配置文件提高了性能。这些工厂配置信息在 Spring Boot 中用于自动装配和初始化各种组件、功能和设置。 这个META-INF/spring.factories文件指什么呢 在我们导入的每一个XXX-spring-boot-starter中除了本身的jar包以外还会有一个 xxx-spring-boot-autoConfigure这个就是第三方依赖自己编写的自动配置类。我们现在就以 spring-boot-autocongigure 这个依赖来说。 这些类就是自动配置的类了。就RedisAutoConfiguration而言 AutoConfiguration
ConditionalOnClass({RedisOperations.class})
EnableConfigurationProperties({RedisProperties.class})
Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {public RedisAutoConfiguration() {}BeanConditionalOnMissingBean(name {redisTemplate})ConditionalOnSingleCandidate(RedisConnectionFactory.class)public RedisTemplateObject, Object redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplateObject, Object template new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;}BeanConditionalOnMissingBeanConditionalOnSingleCandidate(RedisConnectionFactory.class)public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {return new StringRedisTemplate(redisConnectionFactory);}
}里面已经配置好了Redis参数指定了RedisProperties配置文件还有数据源配置文件。 我们只需要在yml文件配置好后面的全交给SpringBoot框架自己配置即可。 4. 常用的Conditional注解
Conditional其实是spring底层注解意思就是根据不同的条件来进行自己不同的条件判断如果满足指定的条件那么配置类里边的配置才会生效。
ConditionalOnClass classpath中存在该类时起效ConditionalOnMissingClass classpath中不存在该类时起效ConditionalOnBean DI容器中存在该类型Bean时起效ConditionalOnMissingBean DI容器中不存在该类型Bean时起效ConditionalOnSingleCandidate DI容器中该类型Bean只有一个或Primary的只有一个时起效ConditionalOnExpression SpEL表达式结果为true时ConditionalOnProperty 参数设置或者值一致时起效ConditionalOnResource 指定的文件存在时起效ConditionalOnJndi 指定的JNDI存在时起效ConditionalOnJava 指定的Java版本存在时起效ConditionalOnWebApplication Web应用环境下起效ConditionalOnNotWebApplication 非Web应用环境下起效 参考 一文搞懂SpringBoot自动配置原理 - 掘金 (juejin.cn)SpringBoot自动配置原理详解 - 掘金 (juejin.cn)