前言
在Spring阶段,我们被各种XML文件配置或者配置类所困扰着,Spring有着“配置地狱”之称
为了简化新 Spring 应用的初始搭建以及开发过程,提出了自动装配的SpringBoot,
该框架遵循“约定优于配置”,使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置
约定优于配置
约定优于配置:按照约定的规范编程,而不是按照配置
以Spring+Mybatis为例:
需要3个文件:Spring基本配置文件(设置自动扫描等)、mybatis配置文件(可以省略)、Spring+mybatis配置文件(bean装配mybatis配置)
mybatis连接数据库的配置必不可少:
<!--DataSource:使用Spring的数据源替换Mybatis的配置
使用spring提供的jdbc
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--绑定Mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--绑定Mapper文件-->
<property name="mapperLocations" value="classpath:com/learn/dao/UserMapper.xml"/>
</bean>
<!--SqlSessionTemplate就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能构造器注入,没有setter方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
而在SpringBoot+Mybatis:
一个application.yml配置文件即可
只需稍微配置:
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: com.learn.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
为什么这么简单就配置好了?
因为在SpringBoot中设置了默认约定,SpringBoot会自动装配好我们需要的东西
如果需要自定义一些配置,在yml文件中配置,即开发人员仅需规定应用中不符合约定的部分,在没有规定配置的地方,采用默认配置
SpringBoot中有哪些约定呢?
- Maven的目录结构:src-main-resources,src-main-java,resources文件夹,存放资源配置文件,java文件夹存放java程序,必须要SpringbootApplication.java同层才能运行。默认的编译生成的类都在targe文件夹下面
- springboot默认的配置文件必须是application.命名的yml文件或者properties文件(可以通过加上-后缀设置不同文件:application-dev.yml)
- application.yml中设置属性需要按层次格式,Spring->datasource->url;mybatis->type-aliases-package等
@SpringBootApplication
SpringBoot有一个启动类SpringbootApplication
package com.springbootweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Springbootweb01Application {
public static void main(String[] args) {
SpringApplication.run(Springbootweb01Application.class, args);
}
}
这是SpringBoot的入口,SpringBoot的启动就是从该main方法启动
它主要加载了@SpringBootApplication注解主配置类
来分析@SpringBootApplication注解
上面四个是元注解,下面的3个是我们需要关注的注解
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM,
classes = TypeExcludeFilter.class), @Filter(type =
FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
@SpringBootConfiguration较简单:
在Spring中就学了,@Configuration注解表示该类为Spring的配置类
这个@SpringBootConfiguration注解功能一样的
@EnableAutoConfiguration
EnableAutoConfiguration,直白的名字:开启自动配置
分析:
该注解上有两个重要的注解:
-
@AutoConfigurationPackage:添加该注解的类所在的package作为自动配置package进行管理
-
@Import(AutoConfigurationImportSelector.class):导入了一个
AutoConfigurationImportSelector选择器给Spring容器中来导入一些组件
@AutoConfigurationPackage注解:导入AutoConfigurationPackages.Registrar注册器
{ @link ImportBeanDefinitionRegistrar } to store the base package from the importing configuration.
就不深入解析了,该注解大致的意思就是:当SpringBoot应用启动时默认会将启动类所在的package作为自动配置的package,所以说我们的包应当和SpringBootApplication类同层
@Import(AutoConfigurationImportSelector.class)
版本为2.2.6 RELEASE,不同的版本有一定的更改
父类里面规定了一个方法叫selectImports方法,查看了selectImports这个方法里面的代码内容就能知道导入了哪些组件:
调用了getAutoConfigurationEntry方法,顾名思义:获得自动装配组件
该方法会返回configurations,这个就是配置对象集合
通过getCandidateConfigurations方法获得,获得候选配置
SpringFactoriesLoader.loadFactoryNames
是这里关键的方法,Spring工厂加载类
该方法会扫描具有META-INF/spring.factories文件的jar包,把这个文件的urls拿到之后并把这些urls遍历,最终把这些文件整成一个properties对象
然后它从properties对象里边获取一些值,把这些获取到的值来加载我们最终要返回的这个结果result,result就是我们要交给Spring容器中的所有组件
factoryTypeName就是我们传过来的Class的这个类名。
是前面SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())
,传入的getSpringFactoriesLoaderFactoryClass()方法中得到,从properties中获取到EnableAutoConfiguration.class类名:
SpringFactoriesLoader会根据这个EnableAutoConfiguration.class去spring.factories找EnableAutoConfiguration.class所对应的values,并返回
spring.factories
META-INF/spring.factories
文件在Spring-boot-autuoconfigure包下
这个配置文件配置了很多自动装配的信息:
这些自动装配类xxxAutoConfiguration都是SpringBoot自动装配的相关类,是SpringBoot自动装配的核心
每个xxxAutoConfiguation类都定义了相关bean的实例化配置,说明了哪些bean可以被自动配置,什么条件下可以自动配置,并把这些bean实例化出来
我们打开一个常见的DataSourceAutoConfiguration,进入查看
- @Configuration(proxyBeanMethods = false):表明这是一个配置类,
proxyBeanMethods = false
表示该类不会被代理,提供性能 - @ConditionalOnClass:当SpringIoC容器内存在指定Class的条件,表示对应的jar包是否导入了,这类注解用来判断是否执行自动装配
- @EnableConfigurationProperties(DataSourceProperties.class):导入对应的启动装配属性类:DataSourceProperties
- @Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class }):相关的配置类
主要就是DataSourceProperties,这个类中定义自动装配的配置:
表示配置前缀是:spring.datasource
内部属性有:
这些就是在application.yml文件中自定义配置的属性:
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
到这,应该明白了 spring.factories的作用:
- 在该文件中配置好SpringBoot需要的自动配置类,当启动SpringBoot时会加载该文件,并一个个加载这些xxxAutoConfiguration类
- 而在这些类中,会有一类ConditionalOnXxx注解判断该类是否自动装配
- 如果是自动装配,会加载EnableConfigurationProperties注解导入的Properties类,该类中会有成员变量,这些变量对应着yml文件可以设置的字段
总结
我们可以大致总结自动配置:
-
SpringBootApplication启动类,是SpringBoot程序的入口,关键在与@SpringBootApplication注解
-
该注解有两个重要的元注解:@SpringBootConfiguration表示该类为Spring的配置类;@EnableAutoConfiguration
-
@EnableAutoConfiguration有两个重要元注解:
@AutoConfigurationPackage表示当SpringBoot应用启动时默认会将启动类所在的package作为自动配置的package
@Import(AutoConfigurationImportSelector.class)导入了一个选择器 -
AutoConfigurationImportSelector的selectImports方法决定SpringBoot导入的组件,经过一系列的方法调用最终会使用SpringFactoriesLoader加载器负责加载配置类名,loadSpringFactories方法读取自动配置工程的META-INF/spring.factories配置文件,加载配置类的全类名,包装成Properties对象,返回result就是交给Spring容器的组件
-
spring.factories内部编写好了全部的自动装配类,启动SpringBoot时,会加载这些自动装配类xxxAutoConfiguration,这些自动装配类有元注解ConditionalOnXxx判断是否自动装配,如果判断确定自动装配,会加载相关的Properties属性类,该属性类属性字段对应yml文件中的字段
学海无涯苦作舟