什么是约定优于配置?自动配置的原理是什么?一文搞懂SpringBoot底层启动流程

什么是约定优于配置?自动配置的原理是什么?一文搞懂SpringBoot底层启动流程



👨‍💻程序员三明治个人主页
🔥 个人专栏: 《设计模式精解》《重学数据结构》

🤞先做到 再看见!


目录

什么是自动配置类?

  • 是指基于你引入的依赖jar包,对Springbo应用进行自动配置
  • 它为SpringBoot框架的“开箱即用”提供了支持

广义的配置类是指:被注解@Component直接或间接修饰的某个类,也就是我们常说的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>com.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=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8 jdbc.username=root jdbc.password=root 
resources下新建mybatis配置文件 mybatis.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 开启延迟加载 该项默认为false,即所有关联属性都会在初始化时加载 true表示延迟按需加载 --><settings><settingname="lazyLoadingEnabled"value="true"/><!-- 开启二级缓存 --><settingname="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" ?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- namespace属性相当于映射文件的名称 属性值任意 接口代理方式,属性值要写成接口的完整类名--><mappernamespace="com.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自带的二级缓存 --><cachesize="1024"eviction="LRU"flushInterval="60000"readOnly="true"/><!-- resultType属性指定结果的类型的完整包名 目前写的是user是因为后期会起一个别名, 默认的别名就是类名的首字母小写 --><selectid="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"?><beansxmlns="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:component-scan base-package="com.tjise.bean"/>--><!-- 加载数据库连接信息的属性文件 --><context:property-placeholderlocation="classpath:jdbc-config.properties"/><!-- 配置Druid数据源的Bean --><beanid="dataSource"class="com.alibaba.druid.pool.DruidDataSource"><propertyname="driverClassName"value="${jdbc.driver}"/><propertyname="url"value="${jdbc.url}"/><propertyname="username"value="${jdbc.username}"/><propertyname="password"value="${jdbc.password}"/></bean><!-- 配置SessionFactory的Bean --><beanid="sessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 注入数据源 --><propertyname="dataSource"ref="dataSource"/><!-- 指定MyBatis配置文件的位置 --><propertyname="configLocation"value="classpath:mybatis.xml"/><!-- 给实体类起别名 --><propertyname="typeAliasesPackage"value="com.tjise.entity"/></bean><!-- 配置mapper接口的扫描器,将Mapper接口的实现类自动注入到IoC容器中 实现类Bean的名称默认为接口类名的首字母小写 --><beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- basePackage属性指定自动扫描mapper接口所在的包 --><propertyname="basePackage"value="com.tjise.mapper"/></bean></beans>
编写测试包和测试类
packagecom.tjise.test;importcom.tjise.entity.User;importcom.tjise.mapper.UserMapper;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.test.context.ContextConfiguration;importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;importjava.util.List;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations ="classpath:spring.xml")publicclassTest_SpringMyBatis{@AutowiredprivateUserMapper userMapper;@TestpublicvoidtestFindUserList(){List<User> userList = userMapper.findUserList();System.out.println(userList);}}

那有了SpringBoot是怎么自动配置的?

SpringBoot自动配置的实例

举一个Redis自动配置的例子

  1. 引入依赖
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.1</version></dependency>
  1. 配置数据源
# 数据源配置 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.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 
  1. 直接在程序中使用RedisTemplate或StringRedisTemplate
@SpringBootTestpublicclassUserMapperTest{@AutowiredprivateUserMapper userMapper;@TestpublicvoidtestFindById(){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容器中

如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家!!

在这里插入图片描述

Read more

昇腾 (Ascend) NPU 实战指南:在 GitCode Notebook 中玩转 CodeLlama

昇腾 (Ascend) NPU 实战指南:在 GitCode Notebook 中玩转 CodeLlama

1.前言 随着大模型技术在软件开发领域的深入应用,越来越多的开发者开始尝试在本地或云端环境部署代码生成模型。华为昇腾(Ascend)计算产业随着 CANN 软件栈的不断成熟,已成为运行各类开源 LLM 的重要算力底座。 本文将以 CodeLlama 这一广受欢迎的代码生成模型为核心,结合 GitCode Notebook 提供的在线开发环境,讲解如何在本地或服务器的昇腾 NPU 环境中完成从依赖配置、模型加载到代码生成的完整流程。文章将通过结构化的流程讲解与可操作的示例代码,引导你在昇腾生态中顺利完成 CodeLlama 的部署与运行。 接下来我们就开始进行动手实践吧。 GitCode官网:https://gitcode.com/。 2.GitCode Notebook 环境准备 GitCode 是面向中国开发者的一站式代码协作与模型应用平台,集成了开源仓库托管、在线运行环境、模型中心等能力。其中的 GitCode Notebook 提供了无需本地配置的云端交互式开发环境,支持直接在浏览器中编写、运行和调试代码,非常适合进行大模型试验与算子验证。 进入Gitcode官网

By Ne0inhk

Git——连接远程仓库

1. 概述         Git连接远程仓库是版本控制中的重要操作,它允许开发者将本地代码库与云端存储平台(如GitHub、GitLab或Bitbucket)进行同步。通过建立远程连接,开发者可以实现多人协作开发、代码备份和版本管理等功能。         连接远程仓库通常涉及以下几个核心步骤: * 创建远程仓库:在代码托管平台新建一个空的仓库 * 获取远程仓库地址:通常有HTTPS和SSH两种协议可选 * 本地配置:在本地Git环境中添加远程仓库信息 * 验证连接:测试本地与远程仓库的通信是否正常         这里只介绍创建完远程仓库之后的连接(创建仓库看主页的另一个笔记),介绍四种:gitee的HTTPS连接、gitee的SSH连接、github的HTTPS连接、github的SSH连接。 2. 前期准备         先初始化git 3. 连接远程仓库 (1)gitee的https连接 git remote add origin <远程仓库地址>        gitee已创建空仓https://gitee.com/kongkongk/ha

By Ne0inhk
解锁时序数据库选型密码,为何国产开源时序数据库IoTDB脱颖而出?

解锁时序数据库选型密码,为何国产开源时序数据库IoTDB脱颖而出?

摘要:本文系统梳理 IoTDB 的缘起、优势、核心功能与生态,指导如何根据业务需求(写入频率、存储规模、实时性等)做选型;并给出 Windows 单机安装、建库插数、查询三步走示例,附上海电气、蓝箭航天、德国铁路三大落地案例,助力快速落地时序数据平台。 目录 1.时序数据库引言 (一)IoTDB是什么 (二)为什么使用IoTDB (三)IoTDB背景 2.选型前的自我审视:明确你的需求 (一)业务场景剖析 (二)关键指标考量 3.核心功能大揭秘:衡量数据库的硬实力 (一)写入性能 (二)数据压缩 (三)查询性能 (四)分布式支持 (五)数据生命周期管理 4.

By Ne0inhk

永久开源免费用!科哥打造的OCR文字检测工具推荐

永久开源免费用!科哥打造的OCR文字检测工具推荐 一款真正开箱即用、无需配置、不收一分钱的OCR文字检测WebUI工具——它不只是一段代码,而是一个完整可交付的生产力解决方案。本文将带你从零开始,快速上手这款由科哥独立开发、持续维护的cv_resnet18_ocr-detection镜像,并深入理解它在真实工作流中能为你省下多少时间。 1. 为什么你需要这个OCR工具? 你是否也经历过这些时刻: * 扫描合同后想快速提取条款,却要反复截图、粘贴、校对; * 整理上百张发票照片,手动录入金额和日期,一坐就是半天; * 做竞品分析时,看到对手宣传页上的关键数据,却没法一键复制; * 学生党整理课堂PPT截图,逐张打字转文字,效率低到怀疑人生。 市面上的OCR服务,要么按次收费、要么限制调用量、要么需要注册企业资质、要么部署复杂得像在搭火箭。而今天介绍的这款工具,没有试用期、没有水印、不联网上传、不依赖云服务、不强制绑定账号——它就安静地运行在你的服务器或本地机器上,点开浏览器就能用。 更关键的是:它不是简单套壳,而是基于ResNet18主干网络+优化检测头的轻量级OC

By Ne0inhk