三、springboot的诞生
1. springboot的目的
鉴于上文提到的越来越多的spring的弊端,尤其是组件版本与组合的问题。必须要好好管理,由此,在spring的基础上,Pivotal团队提供的全新框架——Spring Boot,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。我们举个配置的例子来详细说明。
传统的spring项目,配置基本以xml为主,比如我们要配置数据源,需要如下配置
<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/test"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean>
这是spring自带的数据源类,没有连接池,功能比较薄弱。当然我们可以引入三方包,然后配置成其他数据源类,此处不再赘述。而在springboot中,我们不再以bean的形式维护数据源,而是可以在application.properties里维护
spring: datasource: url: jdbc:mysql://localhost:3306/test driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root
细心观察,你会发现,springboot下,我们没有手动维护数据源的类,这是因为springboot2.x默认采用了HikariCP作为数据源技术(之前是org.apache.tomcat.jdbc.pool.DataSource),而springboot又是怎么采用HikariCP作为默认数据源的呢? 我在下面的特性章节会为你解释。
2. springboot的特性
2.1 starter启动器
如果你用过spring-boot,不难发现,在springboot下,我们引入的包很多都是带着starter的,比如
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.3.12.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <version>2.3.12.RELEASE</version> </dependency>
实际上,这些启动器包大部分本身并不含有代码,而是作为一个依赖管理,为我们引入更具体的其他包。比如spring-boot-starter-jdbc就为我们引入了指定版本的HikariCP组件
当然除了jdbc之外,还有很多启动器包,比如:
- spring-boot-starter-web:包含Spring MVC和Spring WebFlux框架,用于构建Web应用程序。
- spring-boot-starter-amqp:包含Spring AMQP库和RabbitMQ消息代理,用于处理分布式消息传递。
- spring-boot-starter-data-redis:包含Spring Data Redis库,用于处理Redis数据存储和访问。
- spring-boot-starter-test:包含JUnit、Mockito、Hamcrest和Spring Test框架,用于单元测试和集成测试
你或许会问,还是有这么多starter包,如果是新建工程,那不还是得引用很多依赖吗?没错,启动器也是按照模块划分的,并不是一个包就含所有,而是不同模块功能提供一些内置的推荐的组件,让你少点组件版本查询,也少写点些手动依赖。比如说我们说的数据源,它推荐HakariCP,MQ它推荐rabbitMQ。一般在项目初期,如果没有特定组件需求时,采用它默认的就好,后续项目想放弃rabbitMQ,转用rocketMQ,那再替换即可
2.2 自动装配
当我们引入了各类starter包,事情并没有结束,因为是基于spring框架的,很多包引入了以后,我们还需要把加载对应的配置类,然后创建Bean并放入到容器中,对应的功能与配置才算生效
依然以Hakari数据源为例,我们引入了spring-boot-starter-jdbc,也知道该包又引入了Hikari包。那后续呢?这就要提到spring-boot的自动装配功能了。我们把目光放到第一节我们就提及的spring-boot核心包:spring-boot-autoconfigure上
通过这个目录,可以看出,自动装配目前已经覆盖了不少的功能模块,换句话说,你在使用这些功能时,可以享受到自动装配带来的便捷,我们仍用数据源举例。
可以看到,在 DataSourceConfiguration 中,会提供几种数据源,但是因为我们只引了Hikari,所以只有它能被加载,这是 基于其上的 ConditionalOnClass 注解,以及 ConditionalOnProperty 中的matchIfMissing = true参数
@ConditionalOnProperty( name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
这两个注解保证了,在有hikari包的情况下,无需任何显式的配置,就可加载DataSourceConfiguration.Hikari。
@Configuration(proxyBeanMethods = false) @ConditionalOnClass(HikariDataSource.class) @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true) static class Hikari { @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari") HikariDataSource dataSource(DataSourceProperties properties) { HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class); if (StringUtils.hasText(properties.getName())) { dataSource.setPoolName(properties.getName()); } return dataSource; } }
如图加载这个类后,能为我们创建个Bean。那么现在我们知道它能被加载,又是谁真正负责加载它的呢?答案是是自动配置类,而自动配置类的加载流程,其实已经超出spring-boot的范畴,回到了spring加载Bean的机制,所以这里长话短说。spring在使用外部jar包时,会检查jar包里的spring.factories,扫描并加载这文件里提到的类。
如图,加载了DataSourceAutoConfiguration类,而在该自动配置类中,又实用 import 注解引入了这几种数据源类。当然,我们从上面知道,import虽然是import了,但这几个数据源类上又各自有注解,导致最后其实只有hikari成功注册了Bean
2.3 内嵌应用服务器
除了上面提及的一些配置上的自动化,spring备受欢迎的更大原因,是因为其可以内置Tomcat、Jetty或Undertow(无需部署WAR文件),并提供一些默认配置,免去了开发者手动安装和配置应用服务器的烦恼。这在提倡微服务的年代,可谓是如虎添翼
关于spring-boot内嵌服务器的原理,是一个比较庞大的内容,我们后续会专门讲解。
四、总结关联与区别
关联:
- 功能几乎一致:Spring Boot是基于Spring框架,因此可以使用Spring框架提供的所有功能
- 目的一致:简化开发配置,spring是为了简化原始的javaEE模式,而spring-boot则是为了简化spring项目的搭建和配置
区别:
- Spring需要手动引入各种依赖库,并一一确定版本,而Spring Boot则通过各类启动器自动引入依赖库来简化应用的构建,且启动器会帮你确定好匹配的各组件版本。
- Spring依赖于外部的配置文件(如XML、Java Config等),而Spring Boot提供了“约定大于配置”的方式,可以通过默认约定处理常见的配置需求
- Spring Boot可以内嵌应用服务器,独立部署与执行,而spring项目则需要外部提供应用服务器
- 一句话总结:
早期javaEE项目是农村自建住宅,都是房子,但实现与样式各有区别,非常混乱;
spring则是提供了一个标准房图纸,使用它能快速辅助你搭建出一个标准房型,但房子很多细节,比如桌椅门窗仍然需要你自己敲定;
spring-boot则直接是精装商品房,不仅房子是按标准图纸搭建,桌椅门窗等装修也是有默认的一套,可以直接为你装上。