什么是自动配置类?
- 是指基于你引入的依赖jar包,对Springbo应用进行自动配置
- 它为SpringBoot框架的“开箱即用”提供了支持
广义的配置类是指:被注解@***ponent直接或间接修饰的某个类,也就是我们常说的Spring组件,其中包括了@Configuration类
狭义的配置类是指:被注解@Configurantion所修饰的某个类
自动配置原理
其实SpringBoot自动配置的核心,是引导类上加的注解@SpringBootApplication 底层封装的一个注解,叫@EnableAutoConfiguration,这个注解才是实现自动化配置的核心注解。
该注解通过@Import注解导入对应的配置选择器,导入了一个ImportSelector接口的实现类。 而在这个类的内部呢,读取了该项目和该项目引用的Jar包中的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。
在这些配置类中所定义的Bean,会根据条件注解@Condition系列注解所指定的条件来决定是否需要将其导入到Spring容器中。
一般条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的class文件,如果有则加载该类,把这个配置类的所有的Bean放入spring容器中使用。
但是这里要说明一点哈,就是刚才提到的系统配置类声明的配置文件 META-INF/spring.factories, 在springboot3.0版本之后,就已经废除了,不会在这个文件中配置自动配置类了,替换成了一份新的配置文件,配置文件名比较长,记不住,后缀名为:XXxxxSpringAutoConfiguration.imports。
参考链接: 自动配置原理
有没有自动配置的区别在哪?
Spring整合Mybatis
在pom.xml文件中添加jar包的依赖
<dependencies>
<!-- Junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- MyBatis核心Jar包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- MySql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- Lombok工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!-- Spring核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.3</version>
</dependency>
<!-- Spring-test测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.3</version>
<scope>test</scope>
</dependency>
<!-- slf4j日志包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<!-- druid阿里的数据库连接池 -->
<dependency>
<groupId>***.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- Spring整合ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.3</version>
</dependency>
<!-- Spring整合MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
配置MyBatis文件
新建一个实体类的包和User实体类
编写实体类
User的实体类
新建Mapper接口包和UserMapper接口
resouces下新建jdbc资源文件 jdbc-config.properties
jdbc.driver=***.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
resources下新建mybatis配置文件 mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 开启延迟加载 该项默认为false,即所有关联属性都会在初始化时加载
true表示延迟按需加载 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
resources下新建logj4j的日志配置文件log4j.properties
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
新建User的映射mapper文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace属性相当于映射文件的名称 属性值任意
接口代理方式,属性值要写成接口的完整类名-->
<mapper namespace="***.tjise.mapper.UserMapper">
<!-- 开启二级缓存 -->
<!--
<cache
size="1024" //缓存对象的最大个数,默认是1024个
eviction="LRU" //缓存对象的回收策略,默认是LRU算法
//LRU Least Recently Used 最近最少使用,移除最长时间不被使用的对象
//FIFO First In First Out 先进先出,按对象进入缓存的顺序来移除它们
//SOFT 软引用,移除基于垃圾回收器状态和软引用规则的对象
//WEAK 弱引用,更积极地移除基于垃圾收集器和弱引用规则的对象
flushInterval="60000" //自动清空缓存的间隔时间,单位为毫秒,默认是0,表示无穷大
readOnly="true" //缓存对象是否只读,默认为false
//true 从缓存中获取的数据都是只读的,为了加快查询速度,直接返回数据在缓存中的引用,缺点是不安全
//false 从缓存中获取的数据可能会被修改,为了安全起见,利用序列化和反序列的技术克隆一份新的数据返回,缺点是速度慢
/>
-->
<!-- 开启MyBatis自带的二级缓存 -->
<cache
size="1024"
eviction="LRU"
flushInterval="60000"
readOnly="true"
/>
<!-- resultType属性指定结果的类型的完整包名
目前写的是user是因为后期会起一个别名,
默认的别名就是类名的首字母小写 -->
<select id="findUserList" resultType="user">
select * from users
</select>
</mapper>
在UserMapper接口中编写映射文件对应的方法
配置Spring文件
resources下新建spring配置文件spring.xml
i:修改spring.xml—加载数据库连接信息的属性文件
加载上方的jabc-config.properties数据库连接的基础信息
ii:配置Druid数据源的Bean
利用阿里巴巴的数据库连接池,根据上方的jabc-config.properties的文件创建一个dataSource连接信息
iii:配置SqlSessionFactory的Bean,并注入DataSource
把数据库连接存放在工厂中
iiii:配置自动扫描mapper的Bean—MapperScannerConfigurer
把上方的mapper接口文件都自动注入到IoC容器中,实现类Bean的名称默认为接口类名的首字母小写
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--<context:***ponent-scan base-package="***.tjise.bean"/>-->
<!-- 加载数据库连接信息的属性文件 -->
<context:property-placeholder location="classpath:jdbc-config.properties"/>
<!-- 配置Druid数据源的Bean -->
<bean id="dataSource" class="***.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置SessionFactory的Bean -->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 指定MyBatis配置文件的位置 -->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!-- 给实体类起别名 -->
<property name="typeAliasesPackage" value="***.tjise.entity"/>
</bean>
<!-- 配置mapper接口的扫描器,将Mapper接口的实现类自动注入到IoC容器中
实现类Bean的名称默认为接口类名的首字母小写 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- basePackage属性指定自动扫描mapper接口所在的包 -->
<property name="basePackage" value="***.tjise.mapper"/>
</bean>
</beans>
编写测试包和测试类
package ***.tjise.test;
import ***.tjise.entity.User;
import ***.tjise.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring.xml")
public class Test_SpringMyBatis {
@Autowired
private UserMapper userMapper;
@Test
public void testFindUserList(){
List<User> userList = userMapper.findUserList();
System.out.println(userList);
}
}
那有了SpringBoot是怎么自动配置的?
SpringBoot自动配置的实例
举一个Redis自动配置的例子
- 引入依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
- 配置数据源
# 数据源配置
spring.datasource.type=***.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=***.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
- 直接在程序中使用RedisTemplate或StringRedisTemplate
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testFindById() {
User user = userMapper.findById(1);
System.out.println(user);
}
}
可以看到,整个过程中,我们除了通过maven引入一个starter以外,其他都没做,但是SpringBoot就自动完成了Mybatis的配置,将相关的bean对象注册到IOC容器中了。
SpringBoot启动流程的简化版
其中3.加载并处理所有的配置类是核心步骤,具体流程如下
手写springboot的时候,自动配置类需要通过Import注解的方式去引入配置类
那之后我引入很多jar包,难道要去每个jar包下判断有没有AutoConfigurantion结尾的配置类(配置类配好了bean)吗?
很显然不行。这就需要用到Java的SPI机制,就是SpringBoot他约定好了,它启动后只会去jar包下的META-INFO下的spring.factories文件中找。如果你引入的这个jar包确实有自动配置类,那就把自动配置类的名字写在文件里。
文件是以key value的形式保存的,key是自动配置类(把EnableAutoConfigurantion注解的名字当做了key),value是你引入的jar包的自动配置类。
对于我SpringBoot而言,我只需要去文件里去找,找到就说明有自动配置类,value就是引入的jar包的自动配置类的全限定类名
类加载器会加载ConditionalOnclass注解里的这两个类,如果都加载到了,那就表示我需要用到RabbitMQ。如果有一个没加载到,那就表示不需要用到RabbitMQ,我就不需要把配置类的bean加载到bean容器中
如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家!!