6. Spring Boot的starters

6. Spring Boot的starters(重要)

一般认为,SpringBoot 微框架从两个主要层面影响 Spring 社区的开发者们:

  • 基于 Spring 框架的"约定优先于配置(COC)"理念以及最佳实践之路。
  • 提供了针对日常企业应用研发各种场景的 spring-boot-starter 自动配置依赖模块,如此多"开箱即用"的依赖模块,使得开发各种场景的 Spring 应用更加快速和高效。

SpringBoot 提供的这些"开箱即用"的依赖模块都约定以 spring-boot-starter- 作为命名的前缀,并且皆位于 org.springframework.boot 包或者命名空间下(虽然 SpringBoot 的官方参考文档中提到不建议大家使用 spring-boot-starter- 来命名自己写的类似的自动配置依赖模块,但实际上,配合不同的 groupId,这不应该是什么问题)。

如果我们访问 http://start.spring.io,并单击图 1 中的"Switch to the full version"链接,就会发现 SpringBoot1.3.2 默认支持和提供了大约 80 多个自动配置依赖模块。

应用日志和spring-boot-starter-logging

Java 的日志系统多种多样,从 java.util 默认提供的日志支持,到 log4j,log4j2,commons logging 等,复杂繁多,所以,应用日志系统的配置就会比较特殊,从而 spring-boot-starter-logging 也比较特殊一些,下面将其作为我们第一个了解的自动配置依赖模块。

假如 maven 依赖中添加了 spring-boot-starter-logging,如以下代码所示:

<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-logging </artifactId>
</dependency>

那么,我们的 SpringBoot 应用将自动使用 logback 作为应用日志框架,SpringBoot 启动的时候,由 org.springframework.boot.logging.Logging-Application-Listener 根据情况初始化并使用。

SpringBoot 为我们提供了很多默认的日志配置,所以,只要将 spring-boot-starter-logging 作为依赖加入到当前应用的 classpath,则"开箱即用",不需要做任何多余的配置,但假设我们要对默认 SpringBoot 提供的应用日志设定做调整,则可以通过几种方式进行配置调整:

  • 遵循 logback 的约定,在 classpath 中使用自己定制的 logback.xml 配置文件。
  • 在文件系统中任何一个位置提供自己的 logback.xml 配置文件,然后通过 logging.config 配置项指向这个配置文件来启用它,比如在 application.properties 中指定如下的配置。
    logging.config=/{some.path.you.defined}/any-logfile-name-I-like.log

SpringBoot 默认允许我们通过在配置文件或者命令行等方式使用 logging.file 和 logging.path 来自定义日志文件的名称和存放路径,不过,这只是允许我们在 SpringBoot 框架预先定义的默认日志系统设定的基础上做有限的设置,如果我们希望更灵活的配置,最好通过框架特定的配置方式提供相应的配置文件,然后通过 logging.config 来启用。

如果大家更习惯使用 log4j 或者 log4j2,那么也可以采用类似的方式将它们对应的 spring-boot-starter 依赖模块加到 Maven 依赖中即可:

<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-log4j </artifactId>
</dependency>

或者

<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-log4j2 </artifactId>
</dependency>

但一定不要将这些完成同一目的的 spring-boot-starter 都加到依赖中。

快速 Web 应用开发与 spring-boot-starter-web

在这个互联网时代,使用 Spring 框架除了开发少数的独立应用,大部分情况下实际上在使用 SpringMVC 开发 web 应用,为了帮我们简化快速搭建并开发一个 Web 项目,SpringBoot 为我们提供了 spring-boot-starter-web 自动配置模块。

只要将 spring-boot-starter-web 加入项目的 maven 依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

我们就得到了一个直接可执行的 Web 应用,当运行项目就可以直接启动一个使用了嵌入式 tomcat 服务请求的 Web 应用,只不过,我们还没有提供任何服务 Web 请求的 Controller,所以,访问任何路径都会返回一个 SpringBoot 默认提供的错误页面(一般称其为 whitelabel error page),我们可以在当前项目下新建一个服务根路径 Web 请求的 Controller 实现:

@RestController
public class IndexController {
@RequestMapping("/")
public String index() {
return "hello, there";
}
}

重新运行 mvn spring-boot:run 并访问 http://localhost:8080,错误页面将被我们的 Controller 返回的消息所替代,一个简单的 Web 应用就这样完成了。

但是,简单的背后,其实却有很多"潜规则"(约定),我们只有充分了解了这些"潜规则",才能更好地应用 spring-boot-starter-web。

项目结构层面的约定

项目结构层面与传统打包为 war 的 Java Web 应用的差异在于,静态文件和页面模板的存放位置变了,原来是放在 src/main/webapp 目录下的一系列资源,现在都统一放在 src/main/resources 相应子目录下,比如:

  • src/main/resources/static 用于存放各类静态资源,比如 css,js 等。
  • src/main/resources/templates 用于存放模板文件,比如 *.vm。

当然,如果还是希望以 war 包的形式,而不是 SpringBoot 推荐使用的独立 jar 包形式发布 Web 应用,也可以继续原来 Java Web 应用的项目结构约定。

SpringMVC 框架层面的约定和定制

spring-boot-starter-web 默认将为我们自动配置如下一些 SpringMVC 必要组件:

  • 必要的 ViewResolver,比如 ContentNegotiatingViewResolver 和 Bean-NameViewResolver。
  • 将必要的 Converter、GenericConverter 和 Formatter 等 bean 注册到 IoC 容器。
  • 添加一系列的 HttpMessageConverter 以便支持对 Web 请求和相应的类型转换。
  • 自动配置和注册 MessageCodesResolver。
  • 其他。

任何时候,如果我们对默认提供的 SpringMVC 组件设定不满意,都可以在 IoC 容器中注册新的同类型的 bean 定义来替换,或者直接提供一个基于 WebMvcConfigurerAdapter 类型的 bean 定义来定制,甚至直接提供一个标注了 @EnableWebMvc 的 @Configuration 配置类完全接管所有 SpringMVC 的相关配置,自己完全重新配置。

一些特性:
  1. 静态内容支持。可以添加多种静态内容, 例如HTML、JavaScript、CSS、media等等. 静态资源可以放在以下目录下

    1. /static(默认情况下)
    2. /public、
    3. /resources或/META-INF/。
      可以通过修改spring.resources.static-locations 这个属性来改变路径
  2. httpMessageConverter。如果您使用的是常规的Spring MVC, 想要获得JSON响应,则需要JSON的HttpMessageConverters bean. Spring Boot自动添加了Jackson的依赖,并配置好了HttpMessageConverters, 我们直接就可以在程序中使用JSON了。

  3. JSON 处理. 可以通过更改 spring.jackson.date-format 来更改json日期的格式,譬如:

    1. spring.jackson.date-format =yyyy-MM-dd HH:mm:ss #日期格式配置
    2. spring.jackson.time-zone=GMT+8 # 时区配置
  4. 错误处理. 创建404和500页面,那么Spring Boot会自动使用它.

  5. 多种模板引擎支持. 只要加入了依赖 springboot-starter-<模板引擎>,那么就可以直接使用这个模板引擎.

更改一些默认配置
  1. server.port=8081 更改tomcat启动端口号
  2. server.address=10.0.0.1 服务器启动地址. 特别是希望在某个IP上运行时设定
  3. SSL相关配置(HTTPS) 后面有章节介绍
  4. server.port=8443
  5. server.ssl.key-store=classpath:keystore.jks
  6. server.ssl.key-store-password=secret
    server.ssl.key-password=secret
  7. session 相关配置
  8. server.servlet.session.store-dir=/tmp //Session 存储路径
  9. server.servlet.session.persistent=true //Session是否持久化
  10. server.servlet.session.timeout=15 //Session超时时间
  11. server.servlet.session.cookie.name=todo-cookie.dat //session的Cookie名字
    server.servlet.session.cookie.path=/tmp/cookies //Session的Cookie存储路径
  12. Jackson配置
  13. spring.jackson.date-format =yyyy-MM-dd HH:mm:ss #日期格式配置
    spring.jackson.time-zone=GMT+8 # 时区配置

spring-boot-starter-jdbc与数据访问(了解)

大部分 Java 应用都需要访问数据库,尤其是服务层,所以,SpringBoot 会为我们自动配置相应的数据访问设施。

若想 SpringBoot 为我们自动配置数据访问的基础设施,那么,我们需要直接或者间接地依赖 spring-jdbc,一旦 spring-jdbc 位于我们 SpringBoot 应用的 classpath,即会触发数据访问相关的自动配置行为,最简单的做法就是把 spring-boot-starter-jdbc 加为应用的依赖。

默认情况下,如果我们没有配置任何 DataSource,那么,SpringBoot 会为我们自动配置一个基于嵌入式数据库的 DataSource,这种自动配置行为其实很适合于测试场景,但对实际的开发帮助不大,基本上我们会自己配置一个 DataSource 实例,或者通过自动配置模块提供的配置参数对 DataSource 实例进行自定义的配置。

假设我们的 SpringBoot 应用只依赖一个数据库,那么,使用 DataSource 自动配置模块提供的配置参数是最方便的:

spring.datasource.url=jdbc:mysql://{database host}:3306/{databaseName}
spring.datasource.username={database username}
spring.datasource.password={database password}

当然,自己配置一个 DataSource 也是可以的,SpringBoot 也会智能地选择我们自己配置的这个 DataSource 实例(只不过必要性真不大)。

除了 DataSource 会自动配置,SpringBoot 还会自动配置相应的 JdbcTemplate、DataSourceTransactionManager 等关联"设施",可谓服务周到,我们只要在使用的地方注入就可以了:

class SomeDao {
@Autowired
JdbcTemplate jdbcTemplate;
public <T> List<T> queryForList(String sql){
// ...
}
// ...
}

不过,spring-boot-starter-jdbc 以及与其相关的自动配置也不总是带来便利,在某些场景下,我们可能会在一个应用中需要依赖和访问多个数据库,这个时候就会出现问题了。

假设我们在 ApplicationContext 中配置了多个 DataSource 实例指向多个数据库:

@Bean
public DataSource dataSource1() throws Throwable {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(...);
dataSource.setUsername(...);
dataSource.setPassword(...);
// TODO other settings if necessary in the future.
return dataSource;
}
@Bean
public DataSource dataSource2() throws Throwable {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(...);
dataSource.setUsername(...);
dataSource.setPassword(...);
// TODO other settings if necessary in the future.
return dataSource;
}

那么,不好意思,启动 SpringBoot 应用的时候会抛出类似如下的异常(Exception):

Exception):No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2

为了避免这种情况的发生,我们需要在 SpringBoot 的启动类上做点儿"手脚":

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class })
public class UnveilSpringChapter3Application {
public static void main(String[] args) {
SpringApplication.run(UnveilSpringChapter3Application.class, args);
}
}

也就是说,我们需要在这种场景下排除掉对 SpringBoot 默认提供的 DataSource 相关的自动配置。但如果我们还是想要享受 SpringBoot 提供的自动配置 DataSource 的机能,也可以通过为其中一个 DataSource 配置添加 org.springframework.context.annotation.Primary 这个 Annotation 的方式以实现两全其美:

@Bean
@Primary
public DataSource dataSource1() throws Throwable {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(...);
dataSource.setUsername(...);
dataSource.setPassword(...);
// TODO other settings if necessary in the future.
return dataSource;
}
@Bean
public DataSource dataSource2() throws Throwable {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(...);
dataSource.setUsername(...);
dataSource.setPassword(...);
// TODO other settings if necessary in the future.
return dataSource;
}
}

另外,SpringBoot 还提供了很多其他数据访问相关的自动配置模块,比如 spring-boot-starter-data-jpa、spring-boot-starter-data-mongodb 等,大家可以根据自己数据访问的具体场景选择使用这些自动配置模块。

如果选择了 spring-boot-starter-data-jpa 等关系数据库相关的数据访问自动配置模块,并且还需要同时依赖访问多个数据库,那么,也需要相应的在 SpringBoot 启动类中排除掉这些自动配置模块中的 AutoConfiguration 实现类(对应 spring-boot-starter-data-jpa 是 JpaRepositoriesAutoConfiguration),或者标注某个 DataSource 为 @Primary。

附录1 SpringBoot相关模块

相关推荐
_oP_i1 小时前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx1 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
bryant_meng1 小时前
【python】OpenCV—Image Moments
开发语言·python·opencv·moments·图片矩
武子康1 小时前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
若亦_Royi1 小时前
C++ 的大括号的用法合集
开发语言·c++
资源补给站2 小时前
大恒相机开发(2)—Python软触发调用采集图像
开发语言·python·数码相机
豪宇刘2 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意2 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
m0_748247552 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
刘大辉在路上3 小时前
突发!!!GitLab停止为中国大陆、港澳地区提供服务,60天内需迁移账号否则将被删除
git·后端·gitlab·版本管理·源代码管理