SpringBoot 是 Spring 官方当前力推的开发框架,它以合理的默认值,开发者以极少的配置即可快捷地搭建应用,足以让传统的 Spring 开发者拍案叫绝!本文简述了 SpringBoot 的原理和作用,并以实例演示常见 WEB 项目的构建方法,其中包括数据库和 Redis 的接入方法。
作者:王克锋
出处:https://kefeng.wang/2017/12/16/spring-boot/
版权:自由转载-非商用-非衍生-保持署名,转载请标明作者和出处。
1.概述
1.1 作用
Spring Boot 是 Pivotal 团队开发的全新框架,用来简化 Spring 应用的创建和开发过程。
它最小化 Spring 的前期配置,使各组件拥有合理的默认值,开发者只需极少的个性化配置调整,就能满足实际需要。
对于Spring Boot Web 应用程序,默认情况下它使用了一个嵌入式 Tomcat 容器,它既可以独立运行(java -jar 形式),也可以在 J2EE 服务器中运行。
Spring Boot 首版(1.0.0)发布于 2014年4月,当前最新版本为 1.5.9(2017年11月)。
1.2 可替代的传统功能
- 配置 web.xml,加载spring和spring mvc
- 配置数据库连接、配置spring事务
- 配置加载配置文件的读取,开启注解
- 配置日志文件
- …
- 打成 war 包,部署于 Tomcat 运行。
1.3 常用的 starter
每样功能被封装为 starter 形式,而且允许开发者自己开发 starter 再使用。
Spring Boot Starters
Spring Boot:定制自己的starter
- spring-boot-starter: Core starter, including auto-configuration support, logging and YAML
spring-boot-starter-parent: 提供了有用的 Maven 默认设置
spring-boot-starter-aop: Starter for aspect-oriented programming with Spring AOP and AspectJ
- spring-boot-starter-mail: Starter for using Java Mail and Spring Framework’s email sending support
- spring-boot-starter-security: Starter for using Spring Security
spring-boot-starter-test: Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito
spring-boot-starter-logging: Starter for logging using Logback(DEFAULT).
spring-boot-starter-log4j2: Starter for using Log4j2 for logging.
spring-boot-starter-jdbc: Starter for using JDBC with the Tomcat JDBC connection pool
- spring-boot-starter-activemq: Starter for JMS messaging using Apache ActiveMQ
spring-boot-starter-data-redis: Starter for using Redis key-value data store with Spring Data Redis and the Jedis client
spring-boot-starter-web: Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container
- spring-boot-starter-velocity: 对Velocity模板引擎的支持(velocity已废弃)
- spring-boot-starter-freemarker: 对FreeMarker模板引擎的支持
- spring-boot-starter-websocket: Starter for building WebSocket applications using Spring Framework’s WebSocket support
- spring-boot-starter-web-services: Starter for using Spring Web Services
- spring-boot-starter-tomcat: Starter for using Tomcat as the embedded servlet container(DEFAULT used by spring-boot-starter-web).
- spring-boot-starter-jetty: Starter for using Jetty as the embedded servlet container.
- spring-boot-starter-actuator: 添加生产准备特性,比如指标和监控
2.创建工程
2.1 各种创建方法
- https://start.spring.io/: 在线创建、下载、导入;
- Spring Boot CLI: 命令行方式;
- Spring Tool Suite(Eclipse): 创建 Spring Starter Project;
- IntelliJ IDEA: 推荐使用,创建 “Spring Initializr” 项目:
2.2 IntelliJ IDEA 创建工程(hellospring)
- 启用 Spring Boot: 进入菜单 File / Settings, Plugins, 对 “Spring Boot” 打勾(默认没打勾,如果找不到该插件则要先安装),重启 IDEA;
- 创建工程: 进入菜单 File / New / Module, Spring Initializr, 保持默认的 https://start.spring.io 点下一步;
- 修改相关参数,如 Group / Artifact(要求全小写字母) / Java Version(7,8,9) 等,下一步;
- 选择 Spring Boot 版本(默认为稳定版的最高版本),并按分类勾选要引入的 starter;
如 Web/Web, SQL/JDBC|MySQL|MyBatis, NoSQL/Redis, IO/Mail|Kafka, Ops/Actuator - 指定名称和路径,完成。
2.3 基本 pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency><!-- 【可缺省】核心模块,包括自动配置支持、日志和YAML -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency><!-- 支持 WEB -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><!-- 测试模块,包括JUnit、Hamcrest、Mockito -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin><!-- MUST: Maven 构建出来的 jar,war 经过 SpringBoot 重写、增强 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.4 配置文件
全局配置文件 application.properties(可移入 resource/config 目录) 用来修改默认配置:
所有配置参数列表:Common application properties
常用配置参数:
debug=false ## 显示调试信息(出错时有用)、自动配置报告
server.port=8080 ## HTTP 服务监听端口(默认为8080)
### HTTPS
# server.port = 8443
# server.ssl.key-store = classpath:keystore.jks
# server.ssl.key-store-password = secret
# server.ssl.key-password = another-secret
### 响应体的压缩
server.tomcat.compression=on
server.tomcat.compressableMimeTypes=application/json
# 默认使用 logback 为日志框架,这是推荐的方式
spring.main.banner-mode=off
logging.file=webapp.log
logging.level.org.springframework=INFO
logging.pattern.console=%d{HH:mm:ss.SSS} %p [%F:%L] - %m%n
logging.pattern.file=%d{HH:mm:ss.SSS} %p [%F:%L] - %m%n
如果有开发(dev)和线上(prod)两套环境,大部分配置相同,可以采用 profile 机制,
在 application.properties 或命令行中指定环境: spring.profiles.active = dev | prod
- application.properties: 通用配置
- application-dev.properties: 开发环境专用配置
- application-prod.properties: 线上环境专用配置
2.5 应用类 HellospringApplication.java
@SpringBootApplication
是核心注解,它包含以下几个注解:
- @EnableAutoConfiguration
: 根据类路径中的 jar 包依赖为当前项目进行自动配置。
- @SpringBootConfiguration
: 等价于 @Configuration,说明这是一个JavaConfig
- @ComponentScan
: 启用注解自动扫描
@SpringBootApplication
public class HellospringApplication {
// pom.xml 无需手工引入 logback,logback 已自动包含,可直接使用
private Logger logger = LoggerFactory.getLogger(HellospringApplication.class);
public static void main(String[] args) {
logger.info("starting ...");
SpringApplication.run(HellospringApplication.class, args);
}
}
2.6 添加控制类 HellospringController.java
@RestController // 指定数据格式为 JSON(Apache Jackson)
public class HellospringController {
@RequestMapping("/hello")
public String hello() {
return "Hello Spring!";
}
}
2.7 添加单元测试 HellospringApplicationTests.java
代码添加后,直接运行 HellospringApplicationTests.java 会模拟 HTTP 请求,
运行完毕后会报告测试用例通过,或每个失败信息。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest
public class HellospringApplicationTests {
private MockMvc mvc;
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new HellospringController()).build();
}
@Test
public void contextLoads() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/hello"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string(Matchers.equalTo("Hello Spring!")));
}
}
2.8 启动
IDE 中无需配置 Tomcat Server,直接运行应用类的 main() 函数即可。
也可以构建后在命令行运行: java -jar target/hellospring-0.0.1-SNAPSHOT.jar
2.9 浏览
http://localhost:8080/hello
如此简单,所以 Sping Boot 非常适合构建微服务。
它整合了 Spring 框架,并集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等),
这些第三方库几乎可以零配置的开箱即用,只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。
3.Spring Boot 内部机制
在Maven依赖中引入了spring-boot-starter-web,它包含了Spring Boot预定义的一些Web开发的常用依赖:
- spring-web, spring-webmvc Spring WebMvc框架
- tomcat-embed-* 内嵌Tomcat容器
- jackson 处理json数据
- spring-* Spring框架
- spring-boot-autoconfigure: Spring Boot提供的自动配置功能
在SpringApplication.run()方法执行后,Spring Boot的autoconfigure发现这是一个Web应用(根据类路径上的依赖确定),于是在内嵌的Tomcat容器中启动了一个Spring的应用上下文,并且监听默认的tcp端口8080(默认约定)。同时在Spring Context中根据默认的约定配置了Spring WebMvc:
- Servlet容器默认的Context路径是/
- DispatherServlet匹配的路径(servlet-mapping中的url-patterns)是/*
- @ComponentScan路径被默认设置为SampleController的同名package,也就是该package下的所有@Controller,@Service, @Component, @Repository都会被实例化后并加入Spring Context中。
没有一行配置代码、也没有web.xml。基于Spring Boot的应用在大多数情况下都不需要我们去显式地声明各类配置,而是将最常用的默认配置作为约定,在不声明的情况下也能适应大多数的开发场景。
4.接入数据库
4.1 配置数据库
application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/site?useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=site
spring.datasource.password=MySQL5.7
4.2 JdbcTemplate 方式
4.2.1 pom.xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
4.2.2 HellospringController.java
@RestController // 指定数据格式为 JSON(Apache Jackson)
public class HellospringController {
@Autowired
private JdbcTemplate jdbcTemplate;
@RequestMapping("/hello")
public List<Map<String, Object>> hello() {
String sql = "SELECT table_name, table_comment, table_rows, create_time"
+ " FROM information_schema.tables"
+ " WHERE table_schema=DATABASE() AND table_type='BASE TABLE'"
+ " ORDER BY table_name";
return jdbcTemplate.queryForList(sql);
}
}
4.3 Mybatis 方式
4.3.1 配置 MyBatis
application.properties
mybatis.mapperLocations=classpath:mapper/*.xml
4.3.2 配置 starter(pom.xml)
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
4.3.3 生成 MyBatis 相关文件
借助 MyBatis Generator,生成下列文件:
java: entity/MainUsers[Example].java
java: mapper/MainUsersMapper.java
resources: mapper/MainUsersMapper.xml
如果是从其他工程复制过来,注意调整 MainUsersMapper.xml 中的包名。
4.3.4 添加存储类 MainUsersRepository.java
repository/MainUsersRepository.java
@Repository
public class MainUsersRepository {
@Resource
private MainUsersMapper mapper;
public List<MainUsers> getUsers() {
return mapper.selectByExample(null);
}
}
4.3.5 调整控制类 HellospringController.java
@RestController // 指定数据格式为 JSON(Apache Jackson)
public class HellospringController {
@Resource
private MainUsersRepository mainUsersRepository;
@RequestMapping("/hello")
public List<MainUsers> hello() {
return mainUsersRepository.getUsers();
}
}
4.3.6 调整应用类 HellospringApplication.java
// 当 mapper.java 与 Application.java 不同目录时,必须指定 mapper.java 所在包
@MapperScan("wang.kefeng.mapper")
5.接入 Redis
5.1 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
5.2 application.properties
### Redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=passwd
spring.redis.database=0
spring.redis.timeout=3000
spring.redis.pool.min-idle=3
spring.redis.pool.max-idle=8
spring.redis.pool.max-active=16
spring.redis.pool.max-wait=3000
5.3 HellospringController.java
其中的 StringRedisTemplate
相当于 spring-data-redis 中的 RedisTemplate<String, String>
。
@RestController // 指定数据格式为 JSON(Apache Jackson)
public class HellospringController {
@Autowired
private StringRedisTemplate stringTemplate;
@RequestMapping("/hello")
public String hello() {
String name = "test:time";
String value = Long.toString(System.currentTimeMillis());
stringTemplate.opsForValue().set(name, value);
return stringTemplate.opsForValue().get(name);
}
}
6.高级用法
6.1 使用 Jetty 代替 Tomcat
调整 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
</dependencies>
6.2 部署到云端
大多 PaaS 云提供商(Heroku/Cloud Foundry)要求你带上自己的容器,它们管理应用的进程(不特别针对Java应用程序)。
理想情况下,你的应用就像一个Spring Boot可执行jar,所有运行需要的东西都打包到它内部。
Heroku为Java应用分配一个端口,确保能够路由到外部URI。