SpringBoot2自动装配原理解析
作者:小超和你
1、SpringBoot特点
1.1 依赖管理
父项目做依赖管理
springboot项目的父项目 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> </parent> spring-boot-starter-parent的父项目 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.4.RELEASE</version> </parent>
父项目整合了所有开发中常用的依赖的版本号,称为自动版本仲裁机制。
注意:这不是说无需导入依赖了,而是指在导入依赖的时候,会自动仲裁(匹配)版本号,相当于模具的功能。
开发导入starter场景启动器
场景启动器的功能是:springboot已经帮我们整合了所有应用场景常规的依赖,只要依赖中写入某场景启动器,之下的所有依赖也都一一导入了。
- 官方整合的场景启动器一般是:spring-boot-starter-*。
- 只要引入starter,这个场景的所有常规需要的依赖都会自动引入。
- SpringBoot所有支持的场景都在:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter 这个地址里。
- 第三方提供的简化开发的场景启动器一般是:*-spring-boot-starter
- 所有场景启动器都有一个最底层的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.3.4.RELEASE</version> <scope>compile</scope> </dependency>
自动版本仲裁机制
意味着无需关注版本号,即导即用。
注意:
引入父项目中已经整合过的依赖,都可以不写版本号。
但引入没有版本仲裁的jar,需要写版本号。
如果对整合过的依赖的版本号不满意,可以修改默认的版本号,方法如下:
1、查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。 2、在当前项目里面重写配置,如: <properties> <mysql.version>5.1.43</mysql.version> </properties>
1.2 自动配置
springboot已经配置好了那些繁文缛节的配置文件,不用我们额外的配置
比如:
1、Tomcat
2、SpringMVC(引入了全套组件、常用的功能)DispathcherServlet等
3、Web常见功能:字节编码,内部视图解析器
4、默认的扫描包结构
- 之前我们在方法上加注释,需要在配置文件中扫描包名等,现在已经不需要了。
- 主程序Application所在包及其子包里面的组件都会被默认扫描进来
- 如果想要改变扫描路径,可以在主程序上的springboot声明注解中设置scanBasePackages属性
@SpringBootApplication(scanBasePackages="com.atguigu")
public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class,args); } }
5、各种配置拥有默认值
如果需要更改默认值,可以在resource文件下创建application.properties,修改其中的默认值
默认配置的原理:
- 默认配置最终都是映射到某个类上,如:MultipartProperties
- 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
- 引入了哪些场景这个场景的自动配置才会开启
- SpringBoot所有的自动配置功能都在spring-boot-autoconfigure包里面
2、容器功能
2.1 组件添加
1、@Configuration
/** * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的 * 2、配置类本身也是组件 * 3、proxyBeanMethods = true 默认是true 表示代理bean的方法 (动态代理) * Full模式(proxyBeanMethods = true) * Lite模式(proxyBeanMethods = false) * 组件依赖 */ @Configuration(proxyBeanMethods = true) //告诉SpringBoot这是一个配置类 == xml配置文件 public class MyConfig { /** * 外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象 * @return */ //给容器中添加组件,相当于bean标签,以方法名作为组件的id。 返回类型是组件类型,返回值就是组件在容器中的实例。 @Bean public User user01(){ return new User("zhangsan",18); } // 如果不想用方法名作为组件的id 可以修改Bean中的value属性,自定义组件id @Bean("tom") //此时组件id就不再是tomcatPet,而是tom public Pet tomcatPet(){ return new Pet("tomcat"); }
Full模式和Lite模式(新版本增加)
配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
2、@Bean、@Component、@Controller、@Service、@Repository
这些注解与Spring中学习的作用一致,不再解释。
3、@ComponentScan、@Import
ComponentScan是组件扫描的意思。
@Import()
Import注解后面填的是类的数组,作用是给容器中自动创建出这两个类型的组件、且默认组件的名字是全包名。
(可以与@Bean方法创建出的组件是方法名相对比)。
4、@Conditional
条件装配
@ConditionalOnBean(name = "tom")
此注释表示:只有在IOC容器中有tom名称的类才将这个注释挂载的类/方法注册。
2.2、原生配置引入@ImportResource
在一些老的项目或者第三方包引入的时候,很可能还是采用老版的xml方式注册组件,可以在任一配置类上加上此注解,导入xml的地址就可以引入。
使用方式:
1、首先创建xml配置文件,写入一个bean
<bean id="user02" class="com.atguigu.boot.bean.User"> <property name="age" value="20"/> <property name="name" value="xcc"/> </bean>
2、在任意一个配置类上加上@ImportResource注解
@ImportResource("classpath:beans.xml") public class MyConfig { }
2.3 配置绑定
1、@ConfigurationProperties
一些需要抽离的会改变的配置,之前会以properties文件的形式存储,然后通过读取文件,来放入javabean中,但是该注解不必如此麻烦。
只要将需要配置的类加入容器中,再使用@ConfigurationProperties注解,就能够自动将applicaton.properties文件中的属性注入该类。
使用步骤:
1、创建实体类,然后加上@Component注解,将该类注册进容器中。
2、使用@ConfigurationProperties注解,prefix的含义是,所有mycar开头的属性就是要注入的配置内容。
/** * 只有在容器中的组件,才会拥有springboot的强大功能 */ @Component @ConfigurationProperties(prefix = "mycar") public class Car { //一些属性get、set方法云云 }
3、在application.properties中配置需要注入的属性
mycar.brand = BYD mycar.price = 100000
注意:如果该类是引入包里的类,不方便直接在要注入的类上加注释
可以在配置文件中如此声明
@EnableConfigurationProperties(Car.class)
该注释的作用有2个:
1、开启配置绑定功能。
2、把组件自动注册到容器中。
3、自动配置原理入门
3.1 引导加载自动配置类
为什么springboot可以不用我们使用xml文件(仅使用Bean)就可以向容器中注册组件?
原因在于springboot主程序下的声明注解:
@SpringBootApplication
该注解由3个注解复合而成:
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
@SpringBootConfiguration:
这个注解其实就是一个Configuration注解,声明主程序也是一个特殊的配置类。
@ComponentScan
这个注解起到了扫描包的作用,指定扫描包的路径
@EnableAutoConfiguration
@AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}
1、@AutoConfigurationPackage
自动配置包,点进去可以看到:
@Import(AutoConfigurationPackages.Registrar.class) //给容器中导入一个组件 public @interface AutoConfigurationPackage {} //利用Registrar给容器中导入一系列组件 //将指定的一个包下的所有组件导入进来?MainApplication 所在包下。
首先Import导入了一个组件,然后这个组件的功能是用来注册扫描的包下所有的组件。
2、@Import(AutoConfigurationImportSelector.class)
有选择的自动配置一些组件。
1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
4、从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
总的来说:springboot将所有环境的配置全部写在了一个一个工厂的配置文件里。
3.2 按需开启自动匹配项
127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
原理:按照条件装配规则(@Conditional),将选择的配置加载。
3.3 修改默认配置
@Bean @ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件 @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件 public MultipartResolver multipartResolver(MultipartResolver resolver) { //给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。 //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范 // Detect if the user has created a MultipartResolver but named it incorrectly return resolver; }
给容器中加入了文件上传解析器;
springboot帮我们底层封装了一个注解方法,将不符合规范的命名也更正了。
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先。
*******总结********:
- SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置
- 用户直接自己@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面拿值 ----> application.properties
3.4 配置流程
- 引入场景依赖
- https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
- 查看自动配置了哪些(选做)
- 自己分析,引入场景对应的自动配置一般都生效了
- 配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
- 是否需要修改
- 参照文档修改配置项
- https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
- 自己分析。xxxxProperties绑定了配置文件的哪些。
- 自定义加入或者替换组件
- @Bean、@Component。。。
- 自定义器 XXXXXCustomizer;
- .....
4、开发工具
4.1 lombok
lombok可以简化javabean的编写。
当我们创建javabean类的时候,总要编写其getset方法,toString方法、有参无参构造器,很烦而且代码很多不清晰。
可以加lombok注解简化编写。
使用前提:
1、添加lombok的依赖。
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
2、在插件市场安装lombok插件。
使用说明:
@ToString @Data @NoArgsConstructor @AllArgsConstructor public class Pet { private String name; }
@Data:自动编写其get/set方法。
@ToString:自动重写其toString方法。
@NoArgsConstructor:编写无参构造器。
@AllArgsConstructor:编写有参构造器。需要注意的是,有参构造器默认是将所有的参数都构造,如果要想限定个数个参数构造,还是需要自己写。
@Slf4j:日志注解。可以通过log.info在控制台打印消息。
4.2 dev-tools
热更新,在修改了方法或页面时,只需要用dev-tools(Ctrl+F9)就行重新编译,速度要比重启项目快一些
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
4.3 Spring Initailizr(项目初始化向导)
在创建项目的时候,只需要勾选环境,就会自动帮我们搭建项目所需要的环境。
所以我们只需要关注项目本身的代码。
到此这篇关于SpringBoot2自动装配原理的文章就介绍到这了,更多相关SpringBoot2自动装配内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!