旨在通过设计大量的自动化配置等方式来简化Spring 原有样板化的配置,使得开发者可以快速构建应用。
1 介绍
Spring Boot,从本质上将,其实就是spring,它代替我们做了那些以往需要我们自己做的Spring Bean配置。
Spring-boot并没有引入任何形式的代码生成。而是利用了Spring 4的条件化配置特性,以及Maven和gradle提供的传递依赖解析,以实现Spring-boot中的自动配置。
Spring Boot可以把Web应用程序变为可执行的jar文件,而不用部署到传统的Java应用服务器中,就能在命令行中执行。
实现的原理是spring-boot中嵌套了一个Servlet容器(如Tomcat),这是内嵌的Servlet容器提供的功能,并不是Spring-boot实现的。
2 简单的demo
2.1 创建工程
- 目录结构图
- spring initializr初始化项目
- pom文件内容
2.2 目录结构
Spring Boot 的基础结构有三大块:
src/main/java : 主程序入口DemoAppication ,可以通过直接运行该类来启动SPring Boot应用。
src/main/resources:配置目录,该目录用来存放y应用的一些配置信息,比如应用名、服务端口、数据库链接等。引入了web模块,因此会产生static目录与templates目录,前者用于存放静态资源,如图片、CSS文件、JavaScript等;后者用于存放Web页面的模板文件。
src/test/:单元测试目录,生成的DemoApplication通过Junit4实现,可以直接运行的Spring Boot 应用的测试。
3 自动配置
对于很多针对spring应用程序的常见功能,spring boot 能自动提供相关配置。
简单点理解就是可以省略我们在使用spring时的大量配置文件。
3.1 详情简介
SpringBoot利用Spring 4.0提供的条件化配置支持,实现了自动配置。其它应用样例如下:
1:因为Classpath里有H2,所以会创建一个嵌入式的H2数据库Bean,类型为javax.sql.DataSource,JPA实现(Hibernate)需要它来访问数据库;
2:因为Classpath里有Hibernate(Spring Data JPA传递引入的)的实体管理器,所以自动配置会配置与Hibernate相关的Bean,包括Spring的LocalContainerEntityManagerFactoryBean和JpaVendorAdapter;
3:因为Classpath里有SpringDataJPA,所以它会自动配置为根据数据库的接口创建仓库实现;
4:因为Classpath里有Thymeleaf,所以Thymeleaf会配置为SpringMVC的视图,包括一个Thymeleaf的模板解析器、模板引擎及视图解析器。视图解析器会解析相对于Classpath根目录的 /templates目录里的模板;
5:因为Classpath里有SpringMVC(归功于Web起步依赖),所以会配置Spring的DispatcherServlet并启动SpringMVC;
6:因为这是一个Spring MVC Web应用程序,所以会注册一个资源处理器,把相对于Classpath根目录的 /static目录里的静态资源提供出来(还能处理 /public、/resources和 /META-INF/resources的静态内容);
7:因为Classpath里有Tomcat,所以会启动一个嵌入式的Tomcat容器,监听8080端口(默认)。
Spring Boot自动配置承担起了配置Spring的重任,开发者只需专注于自己的应用程序即可。
3.2 实现原理
自动配置,说到底也就是基于spring 4.0的条件化配置,或者说就是利用条件化配置。
以安全配置为例,如果我们没有自定义安全配置的话,如果我们使用了相关注解如@EnableWebSecurity,便会使用默认的安全配置。
如果是我们使用了自定义配置的话则默认的安全配置就会被覆盖。
其中最关键的一个类是SpringBootWebSecurityConfiguration.这个类用了多个注解,其中实现自动配置最关键的一个注解就是@ConditionalOnMissingBean(WebSecurityConfiguration.class);
这个注解的意思是我们这个类要在没有WebSecurityConfiguration这个bean的条件下才会创建。
而在我们自定义安全配置的时候需要自定义类并继承WebSecurityConfigurerAdapter,而这个类是实现了WebSecurityConfigurer接口。
@ConditionalOnMissingBean注解要求当下没有WebSecurityConfiguration类型的 Bean。虽然表面上我们并没有这么一个Bean,但通过在自定义的SecurityConfig上添加@EnableWeb-Security注解,我们实际上间接创建了一个WebSecurityConfiguration Bean。所以在自动 配置时,这个Bean就已经存在了,@ConditionalOnMissingBean条件不成立,SpringBoot- WebSecurityConfiguration提供的配置就被跳过了。
3.3 条件化注解
条件化注解:
条件化注解即配置生效条件 @ConditionalOnBean 配置了某个特定Bean
@ConditionalOnMissingBean 没有配置特定的Bean
@ConditionalOnClass Classpath里有指定的类
@ConditionalOnMissingClass Classpath里缺少指定的类
@ConditionalOnExpression 给定的Spring Expression
Language(SpEL)表达式计算结果为true
@ConditionalOnJava Java的版本匹配特定值或者一个范围值
@ConditionalOnJndi 参数中给定的JNDI位置必须存在一个,如果没有给参数,则要有JNDI InitialContext
@ConditionalOnProperty 指定的配置属性要有一个明确的值
@ConditionalOnResource Classpath里有指定的资源
@ConditionalOnWebApplication 这是一个Web应用程序
@ConditionalOnNotWebApplication 这不是一个Web应用程序
3.4 从数据源获取属性的几种方式
关于几种方式的优先级设置:
这个列表按照优先级排序,也就是说,任何在高优先级属性源里设置的属性都会覆盖低优先 级的相同属性。例如,命令行参数会覆盖其他属性源里的属性。
application.properties和application.yml文件能放在以下四个位置。
(1) 外置,在相对于应用程序运行目录的/config子目录里。
(2) 外置,在应用程序运行的目录里。
(3) 内置,在config包内。
(4) 内置,在Classpath根目录。 同样,这个列表按照优先级排序。
也就是说,/config子目录里的application.properties会覆盖 应用程序Classpath里的application.properties中的相同属性。
此外,如果你在同一优先级位置同时有application.properties和application.yml,那么application. yml里的属性会覆盖application.properties里的属性。
- 命令行参数
- java:comp/env里的JNDI属性
- JVM系统属性
- 操作系统环境变量
- 随机生成的带random.*前缀的属性
- 应用程序以外的application.properties或者appliaction.yml文件
- 打包在应用程序内的application.properties或者appliaction.yml文件
- 通过@PropertySource标注的属性源
- 默认属性
3.5 自动配置微调
- 禁用模板缓存
禁用模板缓存:
首先以thymeleaf模板为例.
有时候我们的程序做了修改,需要重启应用否则对thymeleaf模板的变更不会生效,这是因为thymeleaf默认缓存,这有助于改善应用程序的性能,但是在我们开发过程中确实不太方便,无法实时看到变更的效果。
只需要经spring.thymeleaf.cache设置为false就能够禁用thymelead模板缓存了。
命令行参数方式:
$ java -jar readinglist-0.0.1-SNAPSHOT.jar --spring.thymeleaf.cache=false
这条命令中的readinglist根据实际项目名称变化;
如果希望每次运行时都禁用缓存,可以创建一个application.yml,包含内容:
spring:
thymeleaf:
cache: false
注意发布在正式环境时更改文件。否则生产环境里的应用程序就无法享受模板缓 存带来的性能提升了。
当然,在application.properties文件中配置也是一样可以的;
spring.thymeleaf.cache=false.
除了使用Thymeleaf作为应用程序的视图,Spring Boot支持的其他模板也能关闭模板缓存, 设置这些属性就好了: spring.freemarker.cache(Freemarker) spring.groovy.template.cache(Groovy模板) spring.velocity.cache(Velocity)
默认情况下,这些属性都为true,也就是开启缓存。将它们设置为false即可禁用缓存
- 配置嵌入式服务器
server.port
设置方式和上一个类似,只是设置的参数名不同。
可参考:spring-boot实战51页。 - 配置日志
日志配置,默认情况下spring-boot都是默认十四用logback记录日志的。用其他日志实现替代LogBack,一般来并不需要切换日志实现.如果是需要使用其他的,只需要修改依赖,引入对应日志的起步依赖,同时排除掉LogBack即可。
4 起步依赖
告诉spring boot需要什么功能,它就能引入需要的库。
就比如应用是个Web程序,所以加入web的起步依赖(spring-boot-started-web),仅此一个,他会根据依赖传递把其他需要的依赖都自动添加进来,而并不需要我们手动一个个加入各种依赖。
实际上可以理解为添加了web的起步依赖,就指定了应用程序所需的一类功能。
如果是应用程序使用到JPA持久化,那我们只需要添加jpa的起步依赖就可以了。
Spring Boot起步依赖基本都以spring-boot-starter打头,随后是直接代表其功能的名字,比如web、test。
起步依赖引入的库的版本都是经过了测试的,所以不用担心版本冲突的问题。
4.1 Spring-boot-starter-web
全栈Web开发模块,包含嵌入式Tomcat、Spring MVC.
这里引用的web和test模块,在Spring Boot生态中被称为Starter POMs. Starter POMs是一系列轻便的依赖包,是一套一站式的Spring相关技术的解决方案。开发者在使用和整合模块时,不必再去搜寻各种依赖配置来使用,只需要引用对应的模板包即可。比如开发web应用的时候,那就引入spring-boot-starter-web,希望应用具备访问数据库能力,那就再引入spring-boot-starter-jdbc或是更好用的spring-boot-starter-data-jpa.在使用Spring Boot构建应用的时候,各项功能模块的整合不再像传统Spring应用的开发方式那样,需要再pom.xml中做大量的依赖配置,而是通过Starter POMs定义的依赖包,使得功能模块整合变得非常轻巧,易于理解与使用。
Spring Boot的starter POMs采用spring-boot-starter-*的命名方式,*代表一个特别的应用功能模块,比如Web、test.
4.2 spring-boot-starter-test
通用测试模块,
包含JUnit、Hamcrest、Mockito.
5 命令行界面(CLI)
这是spring boot的可选择性,借此只需要写代码就能完成完整的应用程序,无需传统项目构建。
简单而言,在我们以往开发,在使用某些类时,我们会需要import进行导入,而CLI能够检测到我们使用了哪些类,知道向classpath中添加哪些起步依赖,添加起步依赖之后,就会进行相应的自动配置。
6 Actuator
深入了解运行中的spring boot应用程序。
在运行时检测应用程序内部情况。
包括:
1:Spring应用程序上下文里配置的Bean;
2:Spring-boot的自动配置做的决策;
3:应用程序取到的环境变量、系统属性、配置属性和命令行参数等;
4:应用程序里线程的当前状态;
5:应用程序最近处理过的HTTP请求的追踪情况;
6:各种和内存用量、垃圾回收、Web请求以及数据源用量相关的指标。
Actuator通过web端点和shell界面向外界提供信息。
7 其他
7.1 关于持久化
当我们在使用了Jpa持久化之后,实际上,我们只需要写一个接口继承JpaRespository,在JpaRespository中已经定义了一些方法,如果有需要添加自定义的方法,只需要在继承了JpaRespository中加自己自定义的方法,并再写相应的实现类即可。
为什么继承了JpaRespository接口却不用实现里面已经定义好了的方法参见:
对于JpaRespository已经定义好的方法,并不需要我们去写他们的实现方法,系统能够自动实现,这是因为其中spring-data-jpa中有一个SimpleJpaRepository类就是实现了JpaRespository接口,如果我们继承了JpaRespository的自定义接口没有写相应的实现类,那实现类就是SimpleJpaRepository;如果是写了相应的实现类,那我们的实现类就是我们自定义的实现类,而这又是SimpleJpaRepository的子类,所以在实现类里面也只需要写我们自定义方法的实现类即可,而不用去写那些JpaRespository之前定义好了的方法。