SpringBoot介绍
SpringBoot 对Spring平台和第三方库进行了整合,可创建可以运行的、独立的、生产级的基于Spring的应用程序。(大多数Spring Boot应用程序只需要很少的Spring配置) Spring Boot可以使用java-jar 或者传统的war部署启动的Java应用程序进行创建,可以内嵌Tomcat、Jetty、Undertow容器,快速启动web程序。
设计目标
- 为所有Spring开发提供更快且可通过的入门体验
- 开箱即用,可以根据需求快速调整默认值。
- 提供大型项目(例如嵌入式服务器、运行状况检查和统一配置)通用的一系列非功能性功能
- 绝对没有代码生成,也不需要XML配置。
开始第一个SpingBoot应用-依赖
Maven依赖管理-spring-boot-dependencies提供了SpringBoot支持的依赖,以及相关的版本定义。
<dependencyManagement>
<dependencies>
<dependency>
<!--从SpringBoot导入依赖关系管理-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
示例:引入Web开发相关的依赖(无需再指定版本,由spring-boot-dependencies定义)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId> 自动装在的一些类
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> 一些web相关的类
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
dependencyManagement与dependencies区别
**dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,不用每个模块项目都弄一个版本号,**不利于管理,当需要变更版本号的时候只需要在父类容器里更新,不需要任何一个子项目的修改;如果某个子项目需要另外一个特殊的版本号时,只需要在自己的模块dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。
与dependencies区别:
1)Dependencies相对于dependencyManagement,所有生命在dependencies里的依赖都会自动引入,并默认被所有的子项目继承。
2)**dependencyManagement里只是声明依赖,并不自动实现引入,因此子项目需要显示的声明需要用的依赖。**如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
SpringBoot自动装配
@SpringBootApplication注解
这个注解相当于三个注解的功能集成:
@EnnableAutoConfiguration: 启用Spring Boot的自动bean加载机制
@ComponentScan: 在应用程序所在的包上启用扫描
@Configuration: 允许在Spring中注册额外的bean或导入其他配置类
Spring对类的扫描默认仅涵盖主程序所在的包及子包。
个性化加载配置
条件依赖
- @ConditionalOnClass 应用中包含某个类时,对应的配置才生效
- @ConditionalOnMissingClass 应用中不包含某个类时,对应的配置才生效
- @ConditionalOnBean Spring容器中存在指定的class的实例对象时,对应的配置才生效
- @ConditionalOnMissingBean Spring容器中不存在指定的class的实例对象时,对应的配置才生效
- @ConditionalOnResource 指定文件资源存在时,对应的配置才生效
- @ConitionalOnExpression 指定参数的值符合要求时,对应的配置才会生效。和ConditionalOnProperty的区别在于这个注解使用springEL表达式
先后顺序
- @AutoConfigureAfter 在指定的Configuration类之后加载
- @AutoConfigureBefore 在指定的Configuration类之前加载
- @AutoConfigureOrder 指定该Configuration类的加载顺序,默认值0、
外部参数配置信息加载
Spring 应用程序可以通过属性文件,YAML文件,环境变量和命令行参数等方式的外部化参数配置。
- 启动时命令行传参java-jar app.jar --name=‘test’
- Java系统环境变量
- 配置文件application.properties、application.yml、application-{profile}.properties
环境化配置
profile机制*是什么
1.Spring配置文件提供的一种隔离应用程序配置的方法,使其仅在特定环境中可用。
、2. 可通过profile指定的Bean的应用环境(如开发、测试、生产等环境
- 可通过profile指定不同环境的配置参数值,如配置参数值 spring.prifiles.active=dev或者@Profile(“dev”)注解,实现指定环境下生效
Starter介绍
作用
启动器(Starter)包含许多依赖项,这些依赖项是使项目快速启动和运行所需的依赖项。
例如: 通过配置spring-boot-starter-data-redis,可以快捷的使用Spring对Redis进行数据访问。
命名规范
官方开发的starter遵循类似命名模式;spring-boot-starter-*
第三方starter命名应当遵循thirdpartyproject-spring-boot-starter
常用Starter
- spring-boot-starter-jdbc
- spirng-boot-starter-data-redis
- spring-boot-starter-web
- spring-boot-starter-actuator
自动装配原理解析
1.前言
SpringBoot是目前软件中最主流的框架,无论是工作还是面试基本都有它的身影,SpringBoot主要解决了传统spring的重量级xml配置Bean,实现了自动装配;所以,我们也常在面试中被问到SpringBoot是如何实现自动装配。
2. 源码解析
我们以springboot 2.2.5.RELEASE版本进行解析
2.1 @SpringBootApplication源码解析
先看看springboot启动注解@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 {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
可以看出@SpringBootApplication是由三个注解组成的,@ComponentScan注解则是spring原生注解,其作用是扫描启动类所在的包以及子包所有Bean组件并注册到IOC容器中,两外两个我们再看看源码
@SpringBootConfiguration源码:
@EnableAutoConfiguration源码:
总结@SpringBootApplication注解由三个注解共同完成自动装配,各个注解作用如下
@SpringBootConfiguration: 标记启动类为一个spring配置类
@EnableAutoConfiguration: 实现自动装配的核心注解(重头戏)
@ComponentScan: 扫描启动类所在的包以及子包下所有标记为Bean的组件并注册到IOC容器中
2.2 @EnableAutoConfiguration源码解析
@EnableAutoConfiguration注解才是实现自动装配的核心注解,上面看了他的源码是通过@Import注解导入AutoConfigurationImportSelector类,我们来看看AutoConfigurationImportSelector源码:
通过源码可知,AutoConfigurationImportSelector是ImportSelector的一个字类,@Import注解的一大用处就是导入一个ImportSelector类,通过selectImports方法返回所有需要被注册为bean的类全名的数组集合,具体可以参考我们的上一篇文章@Import注解的详解
我们再来看看AutoConfigurationImportSelector类的selectImports方法
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 判断自动装配开关是否打开
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
首先通过 isEnabled 方法判断自动装配开关是否打开,这里就不细讲了,我们从后面两步开始分析
2.2.1. AutoConfigurationMetadataLoader.loadMetadata() 方法源码分析:
loadMetadata() 方法源码:
META-INF/spring-autoconfigure-metadata.properties文件内容属性:
PropertiesLoaderUtils的 loadProperties 方法源码:
最后创建并返回的AutoConfigurationMetadata对象
综合上述可以得出 AutoConfigurationMetadataLoader.loadMetadata() 方法是用来读取spring-boot-autoconfigure依赖下的
spring-autoconfigure-metadata.properties配置文件内容并封装成一个 AutoConfigurationMetadata 对象
2.2.2 getAutoConfigurationEntry 方法源码分析(重点)
// getAutoConfigurationEntry 方法源码
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
// 再次判断自动装配开关是否打开
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取 @EnableAutoConfiguration注解的 exclude 和 excludeName 属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取该依赖下的 spring.factories配置文件的内容
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 移除重复的数据
configurations = removeDuplicates(configurations);
// 获取spring.autoconfigure.exclude 配置文件的内容并与exclude 和 excludeName 属性合并到一个集合中
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检验configurations中需要排除的内容
checkExcludedClasses(configurations, exclusions);
// 移除configurations中需要排除的内容
configurations.removeAll(exclusions);
// 再次对configurations中的内容进行过滤
configurations = filter(configurations, autoConfigurationMetadata);
// 关闭spring监听器中的自动装配事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
首先依然通过 isEnabled 方法判断自动装配开关是否打开,这里就不细讲了,我们从后面开始分析
getAttributes方法就是获取 @EnableAutoConfiguration注解的 exclude 和 excludeName 属性,由于启动类默认并未设置这两个属性,这里就不再分析
getCandidateConfigurations方法源码分析(重点):
1. SpringFactoriesLoader.loadFactoryNames方法源码:
2. spring.factories配置文件
3. getCandidateConfigurations方法最终返回的结果
removeDuplicates(configurations): 字面上就可以看出是去除重复的元素
getExclusions源码分析
此操作就是将exclude和excludeName属性内容绑定到环境变量去中,由于这两个属性默认为空所以略过
checkExcludedClasses(configurations, exclusions): 方法名上可以知道该方法是检查configurations内容中哪些是需要排除的,由于exclusions默认为空,这里实际没做什么有效的操作,所以不再深入分许
configurations.removeAll(exclusions): 方法名上可以看出是移除需要排除的元素
filter(configurations, autoConfigurationMetadata) 方法源码分析(重点):
fireAutoConfigurationImportEvents(configurations, exclusions): 关闭spring监听器中的自动装配事件
new AutoConfigurationEntry(configurations, exclusions): 最终的返回的结果
综合上述 @EnableAutoConfiguration 注解通过@Import注解导入 ImportSelector 的子类 AutoConfigurationImportSelector 类,该类通过selectImports方法加载读取所有 spring-boot-autoconfigure 依赖下的 spring-autoconfigure-metadata.properties 配置文件和spring.factories 配置文件的内容,并根据 AutoConfigurationImportSelector 类下的 AutoConfigurationImportFilter过滤器的过滤规则和 spring-autoconfigure-metadata.properties 配置文件的内容过滤掉 spring.factories文件中需要被过滤掉的组件元素(当然这之前还有一步根据@EnableAutoConfiguration注解的 exclude 和 excludeName属性过滤 spring.factories 配置文件的内容,由于 @EnableAutoConfiguration注解的这两个属性默认为空,所以这步操作什么都没做),最终返回spring.factories文件中剩余组件的类全名数组,并由IOC容器注册为Bean
- 总结
以上解析了springboot实现自动装配的源码,实际上我们在工作中基本用不到,只需了解即可,我们可能在面试中经常会被问到自动装配的原理,按照以上的解析,这里我们总结一下,面试可以这样简洁回答:
启动类的@SpringBootApplication注解由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三个注解组成,三个注解共同完成自动装配;
**@SpringBootConfiguration 注解标记启动类为配置类
@ComponentScan 注解实现启动时扫描启动类所在的包以及子包下所有标记为bean的类由IOC容器注册为bean
3. 总结
以上解析了springboot实现自动装配的源码,实际上我们在工作中基本用不到,只需了解即可,我们可能在面试中经常会被问到自动装配的原理,按照以上的解析,这里我们总结一下,面试可以这样简洁回答:
启动类的@SpringBootApplication注解由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三个注解组成,三个注解共同完成自动装配;
@SpringBootConfiguration 注解标记启动类为配置类
@ComponentScan 注解实现启动时扫描启动类所在的包以及子包下所有标记为bean的类由IOC容器注册为bean
@EnableAutoConfiguration通过 @Import 注解导入 AutoConfigurationImportSelector类,然后通过AutoConfigurationImportSelector 类的 selectImports 方法去读取需要被自动装配的组件依赖下的spring.factories文件配置的组件的类全名,并按照一定的规则过滤掉不符合要求的组件的类全名,将剩余读取到的各个组件的类全名集合返回给IOC容器并将这些组件注册为bean
原文链接:https://blog.csdn.net/weixin_44947701/article/details/121548373