Spring Boot教程(一) 开发环境搭建

1. 使用向导创建项目

本文使用 IntelliJ IDEA来构建 Spring Boot基础开发环境

  1. File -> new -> Project
    选择 jdk和自动生成目录结构的站点, 点击下一步
    idea创建 spring boot项目 - 1

  2. 添加本地项目的坐标, 构建工具, 构建语言, 打包方式, 项目描述, 项目名称, 项目主包名, 点击下一步
    添加 maven项目坐标

  3. 选择需要的组件, 选择的组件会自动导入相关依赖, 忘记勾选也没有关系, 需要的时候手动在 pom.xml 中添加即可. 选择好之后点击下一步.
    这里只选择了几个基础的组件:
      lombok: 使用注解对 bean快速生成 setter, getter, toString, hashcode等方法, 推荐使用
      web: spring mvc
      thymeleaf: spring默认使用的模板引擎
      freemarker: 另一个使用比较广泛的模板引擎, 使用 Java语言实现
      mysql: mysql 数据库
      mybatis: 半自动的 orm框架
    选中要添加的组件
    这里是自动生成的 pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>cn.com.dom4j</groupId>
    <artifactId>spring_boot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <name>spring_boot</name>
    <description>Demo project for Spring Boot</description>
    
    <!--
      可以通过继承spring-boot-starter-parent项目来获得一些合理的默认配置。
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    
    <dependencies>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
    
        <!-- 当添加此依赖时, 默认就启用了数据库连接池 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
    
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
    
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
    
        <!--
          maven打包的时候会将非 .java文件过滤掉, 这样 mybatis mapper就不能创建成功
          通过如下配置, 可以将 将 src下的 mapper.xml一同打入 jar包
        -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <!-- maven打包插件,可以打成 jar包或 war包 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    </project>
    
  4. 这里是自动生好成的 spring boot项目, 使用 git管理的话, 记得配置一下 .gitignore文件, 这里使用的是 gitignore插件.
    至此一个基础的 spring boot骨架搭建完成. 接下来需要进行的就是相关整合配置.
    自动生成的 spring boot目录结构

2. spring boot与 mybatis集成

2.1 添加组件

在 pom.xml文件中 dependencies 中添加与 mybatis相关的组件
如果在前面通过 spring initializr 生成项目时勾选了 mybatis组件, 则不用再次添加了, 所有的组件同理.

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>

<!-- 
  spring-boot-starter-jdbc 主要给我们提供了 3个功能: 
    1. 对数据源的装配
    2. 提供一个 JdbcTemplate简化我们的使用
    3. 事务支持
  当添加此依赖时, 默认就启用了数据库连接池 
  spring boot 2.0 版本默认使用的连接池是 hikari
-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!-- 添加 mysql jdbc驱动, 其他数据库的话, 请添加对应驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

2.2 配置数据源

将自动生成的 application.properties 配置文件后缀改为 .yml
参考: YAML最最基础语法

在 application.yml中做如下配置
spring boot 的 jdbc模块会加载以下参数, 并且根据 url可以识别并自动加载 mysql驱动, 自动创建数据库实例, 自动实现连接池.

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/youdbname
    username: youusername
    password: youpassword

2.3 配置 mybatis

在 application.yml 中对 mybatis 进行配置

mybatis 相关配置的前缀为 mybatis
 mapper-locations: 指定 mapper文件的位置, /**/ 表示任意目录
 type-aliases-package: 指定要配置别名的类所在的包

mybatis:
  mapper-locations: classpath*:cn/com/dom4j/**/*Mapper.xml
  type-aliases-package: cn.com.dom4j.spring_boot.entity

2.4 编写基础的 crud进行测试

2.4.1 建库建表

create database spring_boot;
use spring_boot;

drop table if exists student;
create table student(
  id int primary key auto_increment,
  name varchar(100) not null comment '姓名',
  age int(3) comment '年龄',
  grade varchar(30) comment '班级',
  number varchar(100) not null comment '学号'
) engine=InnoDB auto_increment=1 default charset=utf8;

2.4.2 实体类

这里使用了 lombok来为我们生成 setter, getter, constructor, toString等
具体用法请参考 Lombok介绍

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Student {
    private int id;
    private String name;
    private int age;
    private String grade;
    private String number;
}

2.4.3 mapper.java

import cn.com.dom4j.spring_boot.entity.Student;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentMapper {
    int addStudent(Student student);
    Student getStudentById(int id);
    int deleteStudentById(int id);
    int updateStudent(Student student);
}

2.4.4 mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="cn.com.dom4j.spring_boot.dao.mapper.StudentMapper">

    <resultMap id="student_result_map" type="cn.com.dom4j.spring_boot.entity.Student">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="grade" column="grade" />
        <result property="number" column="number" />
    </resultMap>

    <sql id="all_field">
        id, name, age, grade, number
    </sql>

    <insert id="addStudent" parameterType="Student">
        insert into student
          (name, age, grade, number)
        VALUE
          (#{name}, #{age}, #{grade}, #{number})
    </insert>

    <delete id="deleteStudentById" parameterType="int">
        delete from student where id = #{id}
    </delete>

    <update id="updateStudent" parameterType="Student">
        update
          student
        set
          <if test="name != null and name.length > 0">
            name = #{name},
          </if>
          <if test="age != null and age > 0">
            age = #{age},
          </if>
          <if test="grade != null and grade.length > 0">
            grade = #{grade},
          </if>
          <if test="number != null and number.length > 0">
            number = #{number},
          </if>
        where
          id = #{id}
    </update>

    <select id="getStudentById" parameterType="int" resultMap="student_result_map">
        select
          <include refid="all_field" />
        from
          student
        where
          id = #{id}
    </select>

</mapper>

2.4.5 dao实现类

import cn.com.dom4j.spring_boot.dao.mapper.StudentMapper;
import cn.com.dom4j.spring_boot.entity.Student;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;

@Repository
public class StudentDao {

    @Resource
    private StudentMapper mapper;

    public int addStudent(Student student) {
        return mapper.addStudent(student);
    }

    public Student getStudentById(int id) {
        return mapper.getStudentById(id);
    }

    public int deleteStudentById(int id) {
        return mapper.deleteStudentById(id);
    }

    public int updateStudent(Student student) {
        return mapper.updateStudent(student);
    }

}

2.4.6 service接口

import cn.com.dom4j.spring_boot.entity.Student;

public interface IStudentService {
    int addStudent(Student student);
    Student getStudentById(int id);
    int deleteStudentById(int id);
    int updateStudent(Student student);
}

2.4.7 service实现类

import cn.com.dom4j.spring_boot.dao.StudentDao;
import cn.com.dom4j.spring_boot.entity.Student;
import cn.com.dom4j.spring_boot.service.IStudentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Slf4j
@Service
public class StudentService implements IStudentService {

    @Resource
    private StudentDao studentDao;

    @Override
    public int addStudent(Student student) {
        int res = -1;
        try {
            res = studentDao.addStudent(student);
        } catch (Exception e) {
            log.error("addStudent error: ", e);
        }
        return res;
    }

    @Override
    public Student getStudentById(int id) {
        Student student = null;
        try {
            student = studentDao.getStudentById(id);
        } catch (Exception e) {
            log.error("getStudentById error: ", e);
        }
        return student;
    }

    @Override
    public int deleteStudentById(int id) {
        int res = -1;
        try {
            res = studentDao.deleteStudentById(id);
        } catch (Exception e) {
            log.error("deleteStudentById error: ", e);
        }
        return res;
    }

    @Override
    public int updateStudent(Student student) {
        int res = -1;
        try {
            res = studentDao.updateStudent(student);
        } catch (Exception e) {
            log.error("updateStudent error: ", e);
        }
        return res;
    }
}

2.4.8 编写测试用例

import cn.com.dom4j.spring_boot.entity.Student;
import cn.com.dom4j.spring_boot.service.IStudentService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;


@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentServiceTest {

    @Resource
    private IStudentService studentService;

    @Test
    public void addStudent() {
        Student student = new Student(4, "王二", 19, "大二", "2014304706");
        int res = studentService.addStudent(student);
        assert res == 1;
    }

    @Test
    public void getStudentById() {
        Student student = studentService.getStudentById(1);
        System.out.println(student);
        assert student != null;
    }
}

2.4.9 完整的项目结构

完整的项目结构

3. mybatis个性化配置

3.1 切换数据库连接池

3.1.1 测试当前使用的连接池

import cn.com.dom4j.spring_boot.entity.Student;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

    @Resource
    private DataSource dataSource;

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Test
    public void DBPoolTest() {
        System.out.println("dataSource  -->  " +  dataSource.getClass().getName());
        // output:  dataSource  -->  com.zaxxer.hikari.HikariDataSource
    }

    @Test
    public void jdbcTemplateTest() {

        DataSource dataSource = jdbcTemplate.getDataSource();
        System.out.println("dataSource  ->  " + dataSource.getClass().getName());

        List<Student> list = jdbcTemplate.query("select * from student", new Object[]{},
                (rs, rowNum) -> new Student(
                        rs.getInt("id"),
                        rs.getString("name"),
                        rs.getInt("age"),
                        rs.getString("grade"),
                        rs.getString("number")
                ));
        /* output: 
           [ 
             Student(id=1, name=小明, age=18, grade=大一, number=2014304706), 
             Student(id=2, name=小明, age=18, grade=大一, number=2014304706), 
             Student(id=3, name=小方, age=19, grade=大二, number=2014304706), 
             Student(id=4, name=王二, age=19, grade=大二, number=2014304706)
           ]
        */

    }
}

3.1.2 查看默认支持的连接池 (内嵌)

注意: spring boot 1.x版本默认使用的连接池是 tomcat-jdbc, 2.x版本中换成了 HikariCP

spring boot 2.0版本默认数据库连接池


查看 DataSourceAutoConfiguration.java得知:
spring boot 2.0支持的连接池有: HikariCP, tomcat-jdbc, commons-dbcp2, Generic
经测试, commons-dbcp, tomcat-dbcp已不再支持

spring boot 2.0默认支持的数据源

3.1.3 切换连接池

第一种方式: 加入连接池依赖, 并在 application.yml 中指定, 这里以 commons-dbcp2为例
推荐使用第一种方式, 简洁明了.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
</dependency>
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/spring_boot
    username: root
    password: dom4j

    type: org.apache.commons.dbcp2.BasicDataSource

第二种方式: 排除 spring-boot-starter-jdbc中的 HikariCP依赖, 并引入自己需要的连接池依赖, 这里以 tomcat-jdbc为例

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <!-- 移除 HikariCP依赖 -->
    <exclusions>
        <exclusion>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- 添加 tomcat-jdbc 连接池 -->
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jdbc</artifactId>
</dependency>

<!-- 
  同样支持 commons-dbcp2连接池, 但 tomcat-jdbc拥有更高的优先级
  经测试, 当 dbcp2 和 tomcat-jdbc同时存在时, 会选用 tomcat-jdbc, 与 pom文件中配置的顺序无关
-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
</dependency>

4. spring boot与 spring mvc集成

4.1 使用 thymeleaf模板引擎

4.2 使用 freemarker模板引擎

4.3 spring mvc个性化配置

5. spring boot 日志管理

5.1 日志配置

application.yml 中日志配置以 logging为前缀

  level: 指定日志级别, 可以配置到包级别, 有如下级别 trace, debug, info, warn, error
  path: 指定日志文件所在路径
  file: 指定日志文件名称, 默认是相对于当前目录 (配置了 file, path就不再生效)
  pattern: 指定日志的输出格式, 可以分别配置控制台和文件中的日志格式.

logging:
  level:
    cn.com.dom4j.spring_boot: trace
  path: /home/bobo
  file: log/spring_boot.log
  pattern:
    console: '%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n'
    file: '%d{yyyy-MM-dd} --> [%thread] %-5level %logger{50} - %msg%n'

日志输出格式

%d: 表示日期时间
%thread: 表示线程名
%level: 表示日志级别    %-5level表示级别从左显示5个字符宽度
%logger: 表示 logger名称,    %logger{50}: 表示 logger名称最长 50个字符, 否则按照句点分割
%msg: 日志信息
%n: 换行符        

日志输出
日志输出

5.2 自定义日志配置文件

使用 logback.xml 作为配置文件

<?xml version="1.0" encoding="UTF-8"?>

<!-- 
根节点 configuration, 包含下面 3个属性
  scan: 当此属性为 true时, 配置文件如果发生改变, 将会被重新加载, 默认值为 true
  scanPeriod: 设置检测配置文件是否有修改的时间间隔, 如果没有给出时间单位, 默认是毫秒.
    当scan为 true时, 此属性生效. 默认的时间间隔为 1分钟
  debug: 当此属性为 true时, 将打印出 logback内部日志信息, 实时查看 logback运行状态. 默认为 false
 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <!--
      contextName: 用来设置上下文名称, 每个 logger都关联到 logger上下文. 默认上下文名称为 default
        但可以使用 contextName设置成其他名字, 用于区分不同应用程序的记录. 一旦设置, 不能修改
     -->
    <contextName>myAppName</contextName>

    <!--
      property: 用来定义变量值, 它有两个属性 name和 value
        通过 property定义的值会被插入到 logger上下文中, 可以通过 '${}'来使用变量
    -->
    <property name="appName" value="myAppName"/>

    <!--
      timestamp: 获取日期时间戳, 它有两个属性: key和 datePattern
        key: 设置此 timestamp的名称
        datePattern: 设置当前时间(解析配置文件的时间)转换为字符串的模式, 遵循 java.txt.SimpleDateFormat的格式
    -->
    <timestamp key="bySecond" datePattern="yyyy-MM-dd HH:mm:ss" />

    <!--
      appender: 负责写日志的组件, 它有两个必要属性 name和 class
        name: 指定 appender的名称
        class: 指定 appender的全限定名
    -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!--
          ConsoleAppender: 把日志输出到控制台, 有以下子节点
            encoder: 对日志进行格式化
            target: 字符串 System.out(默认)或者 System.err
        -->
        <!--
          格式化输出: %d表示日期, %thread表示线程名, %-5level: 级别从左显示5个字符宽度(用于对齐), %msg: 日志消息, %n: 换行符
        -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
        </encoder>
    </appender>

    <!--
      FileAppender: 把日志添加到文件, 有以下子节点
        file: 被写入的文件名, 可以是相对路径, 也可以是绝对路径, 如果上级目录不存在则会自动创建, 没有默认值
        append: 如果是 true, 日志被追加到文件末尾, 如果是 false则覆盖文件, 默认是 true
        encoder: 对记录事件进行格式化
        product: 如果是 true, 日志会被安全的写入文件, 即使其他的 FileAppender也在向此文件做写入操作, 效率低, 默认是 false
    -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>testFile.log</file>
        <append>true</append>
        <encoder>
            <pattern>~</pattern>
        </encoder>
    </appender>

    <!--
      RollingFileAppender: 滚动记录文件, 现将日志记录到指定文件, 当符合某个条件时, 将日志记录到其他文件. 有以下子节点
        file: ~
        append: ~
        rollingPolicy: 当发生滚动时, 决定 RollingFileAppender的行为, 涉及文件名移动和重命名. 属性 class定义具体的滚动策略类
          滚动策略:
            TimeBasedRollingPolicy: 最常用的滚动策略, 它根据时间来指定滚动策略, 既负责滚动也负责触发滚动, 有以下子节点
              fileNamePattern: 必要节点, 包含文件名及 '%d'转换符, '%d'可以包含一个 java.text.SimpleDateFormat指定的日期格式, 如:
                %d{yyyy-MM}, 如果直接使用 %d, 默认格式是 yyyy-MM-dd. RollingFileAppender的 file子节点可有可无, 通过设置 file,
                可以为活动文件和归档文件指定不同位置, 当前日志记录到 file指定的文件(活动文件), 活动文件的名字不会改变;
                如果没有设置 file, 活动文件的名字会根据 fileNamePattern的值, 每隔一段时间改变一次. '/'或 '\'会被当做目录分隔符
              maxHistory: 可选节点, 控制保留的归档文件的最大数量, 超过数量就删除文件. 假设设置每个月滚动, 且 maxHistory是 6,
                则只保留最近6个月的文件, 删除之前的旧文件. 注意: 删除旧文件时, 那些为了归档而创建的目录也会被删除

            SizeBasedTriggeringPolicy: 查看当前活动文件的大小, 如果超过指定大小会告知 RollingFileAppender触发当前活动文件滚动
                只有一个子节点:
              maxFileSize: 活动文件的大小, 默认是 10M

            FixedWindowRollingPolicy: 根据固定窗口算法重命名文件的滚动策略. 有以下子节点
              minIndex: 窗口索引最小值
              maxIndex: 窗口索引最大值, 当用于指定窗口过大时, 会自动将窗口设置为 12
              fileNamePattern: 必须包含 '%i', 例如: 假设最小值和最大值分别为 1和 2, 命名模式为 myLog%i.log, 会产生归档文件
                myLog1.log和 myLog2.log, 还可以指定文件压缩选项, 例如: myLog%i.log.gz或者 myLog%i.log.zip

    -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>~</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>test.log</file>

        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>tests.%i.log.zip</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>3</maxIndex>
        </rollingPolicy>

        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>5MB</maxFileSize>
        </triggeringPolicy>

        <!--
          encoder: 对记录事件进行格式化.负责两件事, 一是把日志信息转换成字节数组, 二是把字节数组写入到输出流
            PatternLayoutEncoder: 是唯一有用且是默认的 encoder, 有一个 pattern节点, 用来设置日志的输入格式.
              使用 '%'加转换符的方式, 如果要输出 '%', 则必须用 '\'对 '%'进行转义
        -->
        <encoder>
            <pattern>~</pattern>
        </encoder>
    </appender>

    <!--
      除了上面说的之外, 还有 SocketAppender, SMTPAppender, DBAppender, SyslogAppender, SiftingAppender, 不过这些并不常用
    -->

    <!--
      logger: 用来设置某一个包或者某一个类的日志打印机别, 以及指定 appender.
            logger仅有一个 name属性, 一个可选的 level和一个宽的 addtivity属性,
            可以包含零个或多个 appender-ref元素, 标识这个 appender将会添加到这个 logger
        name: 用来指定受此 logger约束的一个包或者具体的某一个类
        level: 用来设置打印级别, 大小写无关: trace, debug, info, warn, error, all 和 off,
            还有一个特殊值 inherited或者同义词 null, 代表强制执行行上级的级别. 如果未设置此属性, name当前 logger将会继承上级的级别

        addtivity: 是否向上级 logger传递打印信息. 默认是 true.
          同 logger一样, 可以包含零个或多个 append-ref, 标识这个 appender将会添加到这个 logger

    -->

    <!--
      root: 它也是 logger元素, 但是它是根 logger, 是所有 logger的上级.
            只有一个 level属性, 因为 name已经被命名为 root, 且已经是最上级了
        level: 用来设置打印级别, 大小写无关, trace, debug, info, warn, error, all 和 off, 不能设置为 inherited或者同义词 null
          默认是 debug
    -->
</configuration>

6. spring boot 热部署

使用 spring-boot-devtools 模块来实现热部署

devtools可以实现页面热部署, 即页面修改后会立刻生效, 这个可以在 application.yml文件中配置 spring.thymeleaf.cache = false来实现.
实现类文件热部署 (类文件修改后不会立即生效, 有 1~2秒的延迟)
实现对属性文件的热部署, 即 devtools会监听 classpath下的文件变化, 并且会立刻重启 (发生在文件保存时机, 建议开发时将 devtools关闭, 脑补 idea无限重启, 无限卡顿 …) , 注意因为其采用 虚拟机机制, 该项重启是很快的.

配置了后, 在修改 java文件后也就支持了热启动, 不过这种方式是属于项目重启 (速度比较快的项目重启), 会清空 session的值, 也就是不过有用户登录的话, 项目重启后需要重新登录.

默认情况下, /MATA-INF/maven, /MATA-INF/resources, /static, /templates, /public这些文件夹的修改不会使项目重启, 但是会重新加载 (devtools内嵌了一个 LiveReload, 当资源发生改变时, 浏览器刷新)

6.1 引入模块

添加如下依赖

<!-- 使用 devtools 实现热部署 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

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

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

配置 maven-plugin

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <!-- 配置实现热部署 -->
    <configuration>
        <fork>true</fork>
    </configuration>
</plugin>

6.2 devtools配置

spring:
  devtools:
    restart:
      # 热部署生效
      enabled: true
      # 设置要重启的目录
      additional-paths: src/main/java
      # classpath目录下的 WEB-INF文件夹下的内容修改不重启
      exclude: WEB-INF/**

6.3 idea 配置

当我们修改了 java类后, idea默认是不自动编译的, 而 spring-boot-devtools又是监听 classpath下的文件发生变化时才会重启应用, 所以需要设置 idea的自动编译

File -> Setting -> Build, Execution, Deployment -> Compiler -> 勾选 Build Project autoautomatically
idea配置热部署 - 1

Ctrl + Shift +Alt + / , 选择 Registry, 勾上 Compiler autoMake allow when app running
idea配置热部署 - 2

至此, spring boot的热部署就配置完毕了.

7. spring boot 其他设置

7.1 profile多环境支持

profile是 spring对不同环境提供不同配置功能的支持, 可通过激活, 指定参数等方式快速切换环境

原理是建立多个配置, 然后指定要生效的配置

第一种方式:
  多个配置放在不同的配置文件中, 主配置文件是 application.yml, 其他环境配置文件为 application-{profile}.yml, 放在同一级目录下.

|-- application.yml
|-- application-dev.yml
|-- application-beta.yml
|-- application-prod.yml

application.yml
spring:
  profiles:
    # 指定要使用的配置文件是 application-dev.yml
    active: dev

application-dev.yml
server:
  port: 9091

第二种方式
  将配置所有配置写到同一个配置文件中, yml文件支持多文档块, 通过 --- 来分隔配置, 将主要配置放在最前面, 为每个配置指定名称后, 在主配置中引用即可.

server:
  port: 80

spring:

  profiles:
    active: prod

  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/youdbname?useUnicode=true&amp;characterEncoding=UTF-8
    username: youusername
    password: youpassword

  devtools:
    restart:
      enabled: true
      additional-paths: src/main/java
      exclude: WEB-INF/**

  thymeleaf:
    cache: false

mybatis:
  mapper-locations: classpath*:cn/com/dom4j/**/*Mapper.xml
  type-aliases-package: cn.com.dom4j.spring_boot.entity

---

server:
  port: 8081

spring:
  # 指定该配置块的名称
  profiles: dev

---

server:
  port: 8082
spring:
  profiles: beta

---

server:
  port: 8083
spring:
  profiles: prod

8. 参考

SpringBoot配置devtools实现热部署

posted @ 2018-06-17 20:11  九月清晨-_-  阅读(102)  评论(0)    收藏  举报