一篇进入springboot入门

文章目录

一、springboot工程的概述和构建

1.1.Spring的发展

1.1.1 Spring1.x 时代

在Spring1.x时代,都是通过xml文件配置bean,随着项目的不断扩大,需要将xml配置分放到不同的配置文件中,需要频繁的在java类和xml配置文件中切换。appliationContext.xml 所有的对象和对象之间的关系 全部用xml文件配置!

	<bean id="userDAO" class="com.blog.dao.UserDAOImpl">
		<property name="hibernateTemplate" ref="hibernateTemplate"></property>
	</bean>
	
	<bean id="userService" class="com.blog.service.UserServiceImpl">
		<property name="userDAO">
			<ref bean="userDAO"/>
		</property>
	</bean>
	
	<bean id="loginAction" class="com.blog.action.LoginAction" scope="prototype">
		<property name="userService">
			<ref bean="userService"/>
		</property>
	</bean>

1.1.2 Spring2.x时代

  随着JDK 1.5带来的注解支持,Spring2.x可以使用注解对Bean进行申明和注入,大大的减少了xml配置文件,同时也大大简化了项目的开发。

  • @Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
  • @Scope注解 作用域
  • @Lazy(true) 表示延迟初始化
  • @Service用于标注业务层组件、
  • @Controller用于标注控制层组件(如struts中的action)
  • @Repository用于标注数据访问组件,即DAO组件。
  • @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
  • @Scope用于指定scope作用域的(用在类上)

那么,问题来了,究竟是应该使用xml还是注解呢?

最佳实践

–应用的基本配置用xml,比如:数据源、加载资源文件等;
–业务开发用注解,比如:Service中注入bean等; @Resource @Autowire @Servevice @Controller…

项目:XML(数据源、加载资源文件) + 注解 (@Resource @Autowire @Servevice @Controller…

XML(基础的配置)+注解(对象之前的关系) 开发模式!!

1.1.3 Spring3.x到Spring4.x、Spring5.x

使用Java的类作为一个配置文件把传统 xml配置文件全部替换掉!

从Spring3.x开始提供了Java配置方式(使用Java中一个类来作为配置文件,使用类把XML文件替换),使用Java配置方式可以更好的理解你配置的Bean,现在我们就处于这个时代,并且Spring4.x和Spring boot都推荐使用java配置的方式。

后期开发的时候可以完全不用xml文件。全部用户注解和配置类方式完成

绿皮火车------ Spring XML配置

动车 --------- Spring XML配置 + 注解配置

高铁----------SpringBoot  脚手架  零XML配置   SSM  SSH  SSS   

SpringBoot简化传统的项目搭建方式~

1.2.SpringBoot快速入门

1.2.1.简介

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者的。

SpringBoot封装了底层,使用起来超级简单!底层原理需要看源码!

在以前的spring项目中,都会面对大量繁琐的配置,使用的时候基本上都是大量的复制黏贴。而Spring Boot 则能让我们在不需要过多的配置下,轻松快速地搭建Spring Web应用,开箱即用,没有代码生成,也无需XML配置,从而快速使用spring框架。

以往的spring应用往往需要大量的xml配置,为了改变这一现状spring团队引入了java config(主要依赖@Configuration、@Bean等注解)配置方案,但在整合第三方库时依然需要配置很多固定的Bean,这和xml配置一样仍然有些繁琐,因此spring boot项目应运而生,采用自动化配置方案简化spring应用开发的配置工作。

1.2.2 SpringBoot的特点

  • 为所有 Spring 的开发者提供一个非常快速的、广泛接受的入门体验
  • 绝对没有代码生成,也无需 XML 配置。
  • 快速创建独立运行的Spring项目以及与主流框架集成
  • 使用嵌入式的Servlet容器,应用无需打成WAR包
  • starters(场景启动器)自动依赖与版本控制
  • 大量的自动配置,简化开发,也可修改默认值
  • 无需配置XML,无代码生成,开箱即用
  • 准生产环境的运行时应用监控
  • 与云计算的天然集成
  • 与Spring Cloud (Alibaba)微服务框架天然集成

更多细节,大家可以到官网查看。

在这里插入图片描述
SpringBoot官方文档地址:

https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-documentation-about

1.2.3.HelloWorld

需求:
浏览器发送hello请求,服务器接受请求并处理,响应Hello World字符串;

  • 创建一个Maven工程
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 导入spring boot父工程
    看到这里很多同学会有疑惑,前面说传统开发的问题之一就是依赖管理混乱,怎么这里我们还需要管理依赖呢?难道SpringBoot不帮我们管理吗?

别着急,现在我们的项目与SpringBoot还没有什么关联。SpringBoot提供了一个名为spring-boot-starter-parent的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理,我们的项目需要以这个项目为父工程,这样我们就不用操心依赖的版本问题了,需要什么依赖,直接引入坐标即可!

<?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>com.bruceliu.springboot.hello</groupId>
    <artifactId>springboot-hello</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> 
    </parent>

</project>
  • 导入spring boot 的Web启动器
    为了让SpringBoot帮我们完成各种自动配置,我们必须引入SpringBoot提供的自动配置依赖,我们称为启动器。因为我们是web项目,这里我们引入web启动器:
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 </dependencies>

需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。
这个时候,我们会发现项目中多出了大量的依赖:
在这里插入图片描述
这些都是SpringBoot根据spring-boot-starter-web这个依赖自动引入的,而且所有的版本都已经管理好,不会出现冲突。

  • 管理jdk版本
    默认情况下,maven工程的jdk版本是1.5,而我们开发使用的是1.8,因此这里我们需要修改jdk版本,只需要简单的添加以下属性即可.如果是1.8的JDK,那么可以不配置。
  <properties>
      <java.version>1.8</java.version>
  </properties>
  • 完整的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>com.bruceliu.springboot.hello</groupId>
    <artifactId>springboot-hello</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

</project>
  • 启动类
    Spring Boot项目通过main函数即可启动,我们需要创建一个启动类:
    在这里插入图片描述
    然后编写main函数:
@SpringBootApplication
public class APP {
    public static void main(String[] args) {
        SpringApplication.run(APP.class, args);
    }
}
  • 控制器
    接下来,我们就可以像以前那样开发SpringMVC的项目了!
    我们编写一个controller:
    在这里插入图片描述
    代码:
@RestController
public class HelloController {

    @GetMapping("hello")
    public String hello(){
        return "hello, spring boot!";
    }
}
  • 启动测试
    接下来,我们运行main函数,查看控制台,并且可以看到监听的端口信息:
    在这里插入图片描述
    1)监听的端口是8080
    2)SpringMVC的映射路径是:/
    3)/hello路径已经映射到了HelloController中的hello()方法

  • 测试: 打开页面访问:http://localhost:8080/hello
    在这里插入图片描述

1.2.4.Jar包部署

1.2.4.1.插件支持
<build>
    <plugins>
        <!-- springboot maven打包-->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
1.2.4.2.打包

在这里插入图片描述

1.2.4.3.运行

窗口运行:java -jar xxx.jar
后台运行(linux): nohup java -jar XXX.jar &

1.3.SpringBoot另外构建方式

1.3.1.方法一:在 Spring Boot官方Initializer页面在线构建工程再导入到Idea中

https://start.spring.io/

在这里插入图片描述

1.3.2.方法二:使用IDEA自动构建SpringBoot工程

直接在Idea中Create New Project --> Spring Initializr --> 填写group、artifact -->钩上web --> 点下一步就行了
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

IDE都支持使用Spring的项目创建向导快速创建一个Spring Boot项目;选择我们需要的模块;向导会联网创建Spring Boot项目;

默认生成的Spring Boot项目;

  • 主程序已经生成好了,我们只需要我们自己的逻辑
  • resources文件夹中目录结构
    • static:保存所有的静态资源; js css images;
    • templates:保存所有的模板页面;(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面);可以使用模板引擎(freemarker、thymeleaf);
    • application.properties:Spring Boot应用的配置文件;可以修改一些默认设置;

1.4.自定义Banner

启动Spring Boot项目后会看到这样的图案:
在这里插入图片描述
这个图片其实是可以自定义的:
现在该怎么做呢?

1.打开网站:
http://patorjk.com/software/taag/#p=display&h=1&f=Graffiti

2.拷贝生成的字符到一个文本文件中,并且将该文件命名为banner.txt
将banner.txt拷贝到项目的resources目录中:
在这里插入图片描述
3.重新启动程序,查看效果:
在这里插入图片描述
如果不想看到任何的banner,也是可以将其关闭的:
在这里插入图片描述

二、springboot的配置

SpringBoot全局配置文件默认为src/main/resources下的application.properties,另外它还可以重命名为.yml格式(即SpringBoot对着两种格式均支持)。

properties 属性文件 key=value

yml

2.1.修改默认配置

如修改SpringBoot内嵌Tomcat的启动端口为9080(.yml格式)

server:
  port: 9080

启动项目即可在控制台启动日志中看到

2018-06-24 17:42:25.784  INFO 2658 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9080 (http) with context path ''

这时在浏览器输入localhost:9080即可正常访问

附Spring Boot 全部配置项 SpringBoot Common application properties

数据格式转换: https://www.toyaml.com/index.html

2.2.自定义属性配置

我们也可以在SpringBoot配置文件中自定义属性配置,如

com:
  example:
    girl:
      age: 18
      cupSize: B
      name: hobby

然后通过@Value("${属性名}")注解来加载对应的配置属性

com/example/springbootconfiguration/controller/GirlController.java
package com.bruceliu.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GirlController {

    @Value("${com.example.girl.name}")
    private String girlName;

    @Value("${com.example.girl.age}")
    private Integer girlAge;

    @Value("${com.example.girl.cupSize}")
    private String girlCupSize;

    @GetMapping("/girl")
    public String getGirlInfo() {
        return "girlName: " + girlName + " girlAge: " + girlAge + " girlCupSize: " + girlCupSize;
    }
}

启动工程,访问:localhost:9080/girl,浏览器显示:

girlName: baby girlAge: 18 girlCupSize: B

属性注入成功

2.3.属性配置间的引用

在SpringBoot全局配置文件中的各个属性之间可以通过直接引用来使用

com:
  example:
    girl:
      name: baby
      age: 18
      cupSize: B
      desc: name:${com.example.girl.name} age:${com.example.girl.age} cupSize:${com.example.girl.cupSize}

同样可以使用@Value注解将girl.desc属性配置注入到某一属性中,如

package com.bruceliu.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GirlController {

    @Value("${com.example.girl.name}")
    private String girlName;

    @Value("${com.example.girl.age}")
    private Integer girlAge;

    @Value("${com.example.girl.cupSize}")
    private String girlCupSize;

    @Value("${com.example.girl.desc}")
    private String girlDesc;

    @GetMapping("/girl")
    public String getGirlInfo() {
        // return "girlName: " + girlName + " girlAge: " + girlAge + " girlCupSize: " + girlCupSize;
        return girlDesc;
    }
}

再次启动工程,访问:localhost:9080/girl,浏览器显示:

name:baby age:18 cupSize:B

2.4.将属性配置赋给实体类

当我们属性配置很多的时候,使用@Value注解一个一个的注入将会变得很繁琐,这时SpringBoot提供了将属性配置与实体类结合的方式,具体先来看一下SpringBoot中官方的使用如org.springframework.boot.autoconfigure.data.redis.RedisProperties

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
package org.springframework.boot.autoconfigure.data.redis;

import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(
    prefix = "spring.redis"
)
public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost";
    private String password;
    private int port = 6379;
    private boolean ssl;
    private int timeout;
    private RedisProperties.Pool pool;
    private RedisProperties.Sentinel sentinel;
    private RedisProperties.Cluster cluster;
    
    ...
}

对于上面我们自己关于girl的一些配置,同理我们可以创建一个GirlProperties类,如

package com.bruceliu.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "com.example.girl")
public class GirlProperties {

    private String name;

    private Integer age;

    private String cupSize;
    // ... getter and setters


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getCupSize() {
        return cupSize;
    }

    public void setCupSize(String cupSize) {
        this.cupSize = cupSize;
    }

    @Override
    public String toString() {
        return "GirlProperties{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", cupSize='" + cupSize + '\'' +
                '}';
    }
}

当你在Idea中敲完这些代码Idea可能会提示Spring Boot Configuration Annotation Processor not found in classpath
在这里插入图片描述
点击Open Documentation会打开Generating Your Own Metadata by Using the Annotation Processor页面
嗯,主要是少了个依赖spring-boot-configuration-processor
在这里插入图片描述
在这里插入图片描述
主要是少了个依赖spring-boot-configuration-processor

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

如何使用?在需要使用的类上加@EnableConfigurationProperties注解,同时使用@Autowired注解注入即可,如

package com.bruceliu.controller;

import com.bruceliu.bean.GirlProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableConfigurationProperties(value = {GirlProperties.class})
public class GirlController {

    @Autowired
    private GirlProperties girlProperties;

    @GetMapping("/girl2")
    public GirlProperties getGirlInfo2() {
        return girlProperties;
    }

}

再次启动工程,访问:localhost:9080/girl2,浏览器显示:
在这里插入图片描述

2.5.使用随机值

Spring Boot的属性配置文件中可以通过${random}来产生随机intlonguuid或者string字符串,来支持属性的随机值。
在这里插入图片描述
比如我们给girl随机来个年龄

age: ${random.int}

2.6.自定义配置文件

虽然SprinBoot提供了application.properties或application.yml全局配置文件,但有时我们还是需要自定义配置文件,如将上文关于girl的属性配置提取到girl.properties文件中

girl.name: baby
girl.age: 18
girl.cupSize: B

GirlProperties2.java

package com.bruceliu.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@PropertySource("classpath:girl.properties")
@ConfigurationProperties(prefix = "girl")
public class GirlProperties2 {

    private String name;

    private Integer age;

    private String cupSize;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getCupSize() {
        return cupSize;
    }

    public void setCupSize(String cupSize) {
        this.cupSize = cupSize;
    }

    @Override
    public String toString() {
        return "GirlProperties2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", cupSize='" + cupSize + '\'' +
                '}';
    }
}

GirlController.java

package com.bruceliu.controller;

import com.bruceliu.bean.GirlProperties;
import com.bruceliu.bean.GirlProperties2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableConfigurationProperties(value = {GirlProperties.class, GirlProperties2.class})
public class GirlController {

    @Autowired
    private GirlProperties2 girlProperties2;

    @GetMapping("/girl3")
    public GirlProperties2 getGirlInfo3() {
        return girlProperties2;
    }

}

再次启动工程,访问:localhost:9080/girl3,浏览器显示:
在这里插入图片描述

2.7.多环境配置

实际开发中可能会有不同的环境,有开发环境测试环境生产环境。对于每个环境相关配置都可能有所不同,如:数据库信息、端口配置、本地路径配置等。

如果每次切换不同环境都需要修改application.properties,那么操作是十分繁琐的。在spring boot中提供了多环境配置,使得我们切换环境变得简便。

在Spring Boot中多环境配置文件名需要满足application-{profile}.properties的格式,其中{profile}对应你的环境标识,比如:

application-test.yml:测试环境

server:
  servlet:
    context-path: /test

application-dev.yml:开发环境

server:
  servlet:
    context-path: /dev

application-prod.yml:生产环境

server:
  servlet:
    context-path: /prod

激活profile,在application.yml文件中通过spring.profiles.active属性来设置,其值对应{profile}值,如

spring:
  profiles:
    active: dev

这时启动应用访问localhost:9080/girl3就访问不到了,需访问localhost:9080/dev/girl3才行:
在这里插入图片描述

三、springboot整合mybatis

## 3.1.SpringBoot和MyBatis整合

3.1.2. 准备数据

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for singer
-- ----------------------------
DROP TABLE IF EXISTS `singer`;
CREATE TABLE `singer` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `age` int(3) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `works` varchar(50) NOT NULL,
  `sex` char(1) DEFAULT NULL,
  `idcard` varchar(20) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idcard` (`idcard`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=gbk;

-- ----------------------------
-- Records of singer
-- ----------------------------
INSERT INTO `singer` VALUES ('1', '汪峰', '50', '2010-10-10', '飞得更高', '男', '34535434535675467567');
INSERT INTO `singer` VALUES ('2', '小A', '18', '2010-10-20', '双杰伦', '男', '345354345356754673');
INSERT INTO `singer` VALUES ('3', '哈林', '56', '2010-11-10', '情非得已', '男', '3453543453567543');
INSERT INTO `singer` VALUES ('4', '娜姐', '60', '2010-10-13', '征服', '女', '345354345356754676');
INSERT INTO `singer` VALUES ('7', '小A', '18', '2001-10-10', '乡村爱情进行曲', '男', '3454354354354385');
INSERT INTO `singer` VALUES ('8', '赵四', '55', '2001-10-10', '乡村爱情进行曲', '男', '3454354354354775');
INSERT INTO `singer` VALUES ('9', '赵四', '55', '2001-10-10', '乡村爱情进行曲', '男', '3454354366664775');
INSERT INTO `singer` VALUES ('10', '小沈阳', '55', '2001-10-10', '乡村爱情进行曲', '男', '3554354366664775');
INSERT INTO `singer` VALUES ('11', '小花', '18', '2010-10-13', '协奏曲', '女', '23423423424324');

3.1.2. 加入依赖

<!--导入MyBatis的场景启动器-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.28</version>
        </dependency>

3.1.3. 加入Mapper接口

import com.bruceliu.bean.Singer;

import java.util.List;

/**
 * @BelongsProject: SpringBoot-helloworld
 * @BelongsPackage: com.bruceliu.mapper
 * @CreateTime: 2020-10-19 15:23
 * @Description: TODO
 */
public interface SingerMapper {

    List<Singer> findSingers();
}

3.1.4. 加入Mapper接口XML文件

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bruceliu.mapper.SingerMapper">

    <select id="findSingers" resultType="com.bruceliu.bean.Singer">
        select * from singer
    </select>

</mapper>

3.1.5. 数据库配置信息

# 配置数据的连接信息
spring.datasource.url=jdbc:mysql://127.0.0.1/singerdb?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource


#MyBatis参数配置
# 指定Mapper.xml位置
mybatis.mapper-locations=classpath:mappers/*.xml
# 给实体类取别名
mybatis.type-aliases-package=com.bruceliu.bean

3.1.6 Mapper接口注解

@Mapper
public interface SingerMapper {

    List<Singer> findSingers();
}

3.2.SpringBoot执行单元测试

3.2.1.导入测试依赖

<!--SpringBoot和Junit整合-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

3.2.2.测试类

@RunWith(SpringRunner.class) //测试SpringBoot框架。启动SpringBoot框架
@SpringBootTest(classes = APP.class)
public class TestMyBatis {

    @Resource
    SingerMapper singerMapper;

    @Test
    public void test1(){
        List<Singer> singers = singerMapper.findSingers();
        for (Singer singer : singers) {
            System.out.println(singer);
        }
    }

}

四、springboot整合thymeleaf

## 4.1.Thymeleaf简介

Thymeleaf是跟Velocity、FreeMarker类似的模板引擎,它可以完全替代JSP,相较与其他的模板引擎,它主要有以下几个特点:

  1. Thymeleaf在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以thymeleaf的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。

  2. Thymeleaf开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。

  3. Thymeleaf提供spring标准方言和一个与SpringMVC完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。

Thymeleaf官网:http://www.thymeleaf.org

4.2.Thymeleaf整合SpringBoot

  1. 在pom.xml文件引入thymeleaf
<dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. 在application.properties(application.yml)文件中配置thymeleaf
# thymeleaf 
spring.thymeleaf.prefix=classpath:/templates/ 
spring.thymeleaf.check-template-location=true 
spring.thymeleaf.suffix=.html 
spring.thymeleaf.encoding=UTF-8 
spring.thymeleaf.content-type=text/html 
spring.thymeleaf.mode=HTML5 
spring.thymeleaf.cache=false
  1. 新建编辑控制层代码HelloController,在request添加了name属性,返回到前端hello.html再使用thymeleaf取值显示。
@Controller 
public class HelloController {
    
    @RequestMapping("/hello") 
    public String hello(HttpServletRequest request, @RequestParam(value = "name", defaultValue = "springboot-thymeleaf") String name) { 
        request.setAttribute("name", name); 
        return "hello"; 
    } 
}
  1. 新建编辑模板文件,在resources文件夹下的templates目录,用于存放HTML等模板文件,在这新增hello.html,添加如下代码。
<!DOCTYPE html> 
<html lang="en" xmlns:th="http://www.thymeleaf.org"> 
<head> 
    <meta charset="UTF-8"/> 
    <title>springboot-thymeleaf demo</title> 
</head> 

<body> 
    <p th:text="'hello, ' + ${name} + '!'" /> 
</body> 
</html>

切记:使用Thymeleaf模板引擎时,必须在html文件上方添加该行代码使用支持Thymeleaf。

<html lang="en" xmlns:th="http://www.thymeleaf.org"> 
  1. 启动项目,访问http://localhost:8080/hello,看到如下显示证明SpringBoot整合Thymeleaf成功。

在这里插入图片描述

五、springboot整合swagger2

5.1.引言

由于Spring Boot能够快速开发、便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API。而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端。

这样一来,我们的RESTful API就有可能要面对多个开发人员或多个开发团队:IOS开发、Android开发或是Web开发等。为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTful API文档来记录所有接口细节,然而这样的做法有以下几个问题:

  • 由于接口众多,并且细节复杂(需要考虑不同的HTTP请求类型、HTTP头部信息、HTTP请求内容等),高质量地创建这份文档本身就是件非常吃力的事,下游的抱怨声不绝于耳。
  • 随着时间推移,不断修改接口实现的时候都必须同步修改接口文档,而文档与代码又处于两个不同的媒介,除非有严格的管理机制,不然很容易导致不一致现象。

为了解决上面这样的问题,本文将介绍RESTful API的重磅好伙伴Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API。具体效果如下图所示:
在这里插入图片描述下面来具体介绍,如果在Spring Boot中使用Swagger2。

5.2.需求准备

回顾并详细说明一下在SpringMVC中使用的@Controller、@RestController、@RequestMapping注解。

@Controller:修饰class,用来创建处理http请求的对象
@RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseBody来配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,默认返回json格式。
@RequestMapping:配置url映射

下面我们尝试使用Spring MVC来实现一组对User对象操作的RESTful API,配合注释详细说明在Spring MVC中如何映射HTTP请求、如何传参、如何编写单元测试。

在这里插入图片描述准备工程
在这里插入图片描述项目依赖

<?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>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.bruceliu.springboot.swagger2</groupId>
    <artifactId>springboot-swagger2</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class APP {
    public static void main(String[] args) {
        SpringApplication.run(APP.class,args);
    }
}

实体类

public class User {

    private Long id;
    private String name;
    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

实现对User对象的操作接口

@RestController
@RequestMapping(value="/users")     // 通过这里配置使下面的映射都在/users下 
public class UserController {

    // 创建线程安全的Map 
    static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

    @RequestMapping(value="/", method=RequestMethod.GET)
    public List<User> getUserList() {
        // 处理"/users/"的GET请求,用来获取用户列表 
        // 还可以通过@RequestParam从页面中传递参数来进行查询条件或者翻页信息的传递 
        List<User> r = new ArrayList<User>(users.values());
        return r;
    }

    @RequestMapping(value="/", method= RequestMethod.POST)
    public String postUser(@ModelAttribute User user) {
        // 处理"/users/"的POST请求,用来创建User 
        // 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数 
        users.put(user.getId(), user);
        return "success";
    }

    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public User getUser(@PathVariable Long id) {
        // 处理"/users/{id}"的GET请求,用来获取url中id值的User信息 
        // url中的id可通过@PathVariable绑定到函数的参数中 
        return users.get(id);
    }

    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public String putUser(@PathVariable Long id, @ModelAttribute User user) {
        // 处理"/users/{id}"的PUT请求,用来更新User信息 
        User u = users.get(id);
        u.setName(user.getName());
        u.setAge(user.getAge());
        users.put(id, u);
        return "success";
    }

    @RequestMapping(value="/{id}", method=RequestMethod.DELETE)
    public String deleteUser(@PathVariable Long id) {
        // 处理"/users/{id}"的DELETE请求,用来删除User 
        users.remove(id);
        return "success";
    }

}

5.3.整合swagger2

5.3.1.导入依赖

在pom.xml中加入Swagger2的依赖

         <!-- swagger-spring-boot -->
		<dependency>
			<groupId>com.spring4all</groupId>
			<artifactId>swagger-spring-boot-starter</artifactId>
			<version>1.7.0.RELEASE</version>
		</dependency>

5.3.2.application.yml配置

在Application.java同级创建Swagger2的配置类Swagger2。

swagger.base-package=com.bruceliu.controller
swagger.title=JAVA1908哈哈哈Swagger!!!
swagger.contact.name=BRUCELIU
swagger.contact.url=http://www.bruceliu.com
swagger.version=2.3

通过@EnableSwagger2Doc注解来启用Swagger2。

5.3.3.添加文档内容

在完成了上述配置后,其实已经可以生产文档内容,但是这样的文档主要针对请求本身,而描述主要来源于函数等命名产生,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容。如下所示,我们通过@ApiOperation注解来给API增加说明、通过@ApiImplicitParams@ApiImplicitParam注解来给参数增加说明。

@RestController
@RequestMapping(value = "/users")     // 通过这里配置使下面的映射都在/users下
public class UserController {

    // 创建线程安全的Map
    static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

    @ApiOperation(value = "获取用户列表", notes = "")
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public List<User> getUserList() {
        // 处理"/users/"的GET请求,用来获取用户列表
        // 还可以通过@RequestParam从页面中传递参数来进行查询条件或者翻页信息的传递
        List<User> r = new ArrayList<User>(users.values());
        return r;
    }

    @ApiOperation(value = "创建用户", notes = "根据User对象创建用户")
    @ApiImplicitParam(name = "user", value = "用户详细实体user", required = false, dataType = "User")
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public String postUser(@ModelAttribute User user) {
        // 处理"/users/"的POST请求,用来创建User
        // 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数
        users.put(user.getId(), user);
        return "success";
    }

    @ApiOperation(value = "获取用户详细信息", notes = "根据url的id来获取用户详细信息")
    @ApiImplicitParam(name = "id", value = "用户ID", required = false, dataType = "Long")
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public User getUser(@PathVariable Long id) {
        // 处理"/users/{id}"的GET请求,用来获取url中id值的User信息
        // url中的id可通过@PathVariable绑定到函数的参数中
        return users.get(id);
    }

    @ApiOperation(value = "更新用户详细信息", notes = "根据url的id来指定更新对象,并根据传过来的user信息来更新用户详细信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long"),
            @ApiImplicitParam(name = "user", value = "用户详细实体user", required = false, dataType = "User")
    })
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public String putUser(@PathVariable Long id, @ModelAttribute User user) {
        // 处理"/users/{id}"的PUT请求,用来更新User信息
        User u = users.get(id);
        u.setName(user.getName());
        u.setAge(user.getAge());
        users.put(id, u);
        return "success";
    }

    @ApiOperation(value = "删除用户", notes = "根据url的id来指定删除对象")
    @ApiImplicitParam(name = "id", value = "用户ID", required = false, dataType = "Long")
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public String deleteUser(@PathVariable Long id) {
        // 处理"/users/{id}"的DELETE请求,用来删除User
        users.remove(id);
        return "success";
    }

}

5.3.4.需要在启动类中添加注解

@SpringBootApplication
@EnableSwagger2Doc
public class APP {
    public static void main(String[] args) {
        SpringApplication.run(APP.class,args);
    }
}

5.3.5.需要在启动类中添加注解

完成上述代码添加上,启动Spring Boot程序,访问:http://localhost:8080/swagger-ui.html
。就能看到前文所展示的RESTful API的页面。我们可以再点开具体的API请求,以POST类型的/users请求为例,可找到上述代码中我们配置的Notes信息以及参数user的描述信息,如下图所示。
在这里插入图片描述

5.3.6.API文档访问与调试

在上图请求的页面中,我们看到user的Value是个输入框?是的,Swagger除了查看接口功能外,还提供了调试测试功能,我们可以点击上图中右侧的Model Schema(黄色区域:它指明了User的数据结构),此时Value中就有了user对象的模板,我们只需要稍适修改,点击下方“Try it out!”按钮,即可完成了一次请求调用!
在这里插入图片描述
此时,你也可以通过几个GET请求来验证之前的POST请求是否正确。

相比为这些接口编写文档的工作,我们增加的配置内容是非常少而且精简的,对于原有代码的侵入也在忍受范围之内。因此,在构建RESTful API的同时,加入swagger来对API文档进行管理,是个不错的选择。

六、springboot日志框架管理

## 6.1.为什么需要日志框架

通过日志的方式记录系统运行的过程或错误以便定位问题。

6.2.常见日志框架

6.2.1.日志框架介绍

对于我们日常开发日志是经常使用的,当然以前的我们可能还傻傻的各种System.out.println("重要数据")在控制台输出各种重要数据呢,投入生产的时候再注释掉。到现在为止呢,已经有很多日志可供选择了,而市面上常见的日志框架有很多,比如:JCLSLF4JJboss-loggingjULlog4jlog4j2logback等等,我们该如何选择呢?

6.2.2.市面上的日志框架

JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j…

日志的抽象层日志实现
JCL(Jakarta Commons Logging) SLF4j(Simple Logging Facade for Java) jboss-loggingLog4j JUL(java.util.logging) Log4j2 Logback

左边选一个抽象层、右边来选一个实现;类似与我们经常使用的JDBC一样,选择不同的数据库驱动。

下面我们先看看日志的抽象层:JCL大家应该很熟悉,Commons Logging,spring中常用的框架最后一次更新2014年~~~;jboss-logging使用的场景太少了;就剩下SLF4j了也是我们springboot中使用的日志抽象层。

日志实现:大家应该看着都很熟悉把Log4j大家应该用的挺多的,Logback是Log4j的升级版本出至于同一个人开发的,考虑到以后的升级使用等问题,又写出了SLF4j的日志抽象层使用起来更加灵活。JUL(java.util.logging)一看就知道是java util包下的;Log4j2 咋一看像是Log4j的升级版本,其实并不是,它是apache下生产的日志框架。

SpringBoot底层是Spring框架, Spring框架默认使用JCL.
SpringBoot选用SLF4j和Logback

6.3.Slf4j使用

6.3.1.如何在系统中使用SLF4j

slf4j官网: https://www.slf4j.org

开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法;
给系统里面导入slf4j的jar和 logback的实现jar就可以。

使用示例

public class HelloWorld {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(HelloWorld.class);
        logger.info("Hello World");
    }
}

在这里插入图片描述
在这里插入图片描述
我们现在已经知道了springboot中使用的是 SLF4j和logback,但是如果我们想使用log4j该怎么办呢,从上面的图示中我们可以看出想要使用log4j我们肯定还是要使用 SLF4j作为抽象层,但是中间给我们加入了一层适配层(Adaptation layer)然后使用log4j进行实现,那么我们需要导入图示中的jar包即可,其他的也是一样了。所以说,以后开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法每一个日志的实现框架都有自己的配置文件。使用slf4j以后,配置文件还是做成日志实现框架自己本身的配置文件

6.3.2.可能存在的问题

现在开发中我么想使用slf4j+logback,但是对于一些遗留项目中例如Spring(commons-logging)、Hibernate(jboss-logging)…等等,如何去做到日志同一呢?

你想到的问题SLF4j能想不到吗?答案是可以的,我们看看下面的图就明白了
在这里插入图片描述
在这里插入图片描述
如何让系统中所有的日志都统一到slf4j;

1、将系统中其他日志框架先排除出去;
2、用中间包来替换原有的日志框架;
3、我们导入slf4j其他的实现

其实通过idea我们创建一个springboot项目也可以查看日志依赖(截取其中部分):
SpringBoot使用它来做日志功能:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>1.3.2.RELEASE</version>
     <relativePath/> <!-- lookup parent from repository -->
</parent>

总结:
  1)、SpringBoot底层也是使用slf4j+logback的方式进行日志记录
  2)、SpringBoot也把其他的框架的日志都替换成了slf4j;
  3)、如果我们要引入其他框架?
  
SpringBoot能自动适配所有的日志,而且底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉即可

示例:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
	<exclusions>
		<exclusion>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>

6.4.SpringBoot日志的默认配置

SpringBoot日志的默认配置的位置:
在这里插入图片描述
在这里插入图片描述

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

    // 日志记录器
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Test
    public void contextLoads() {
        // System.out.println();
        // 日志的级别:由低到高
        // trace<debug<info<warn<error
        // 可以调整需要输出的日志级别: 日志就只会在这个级别及以后的高级别生效
        logger.trace("这是trace日志...");
        logger.debug("这是debug日志...");
        // SpringBoot默认使用的是info级别的, 没有指定级别的就使用SpringBoot默认规定的级别
        logger.info("这是info日志...");
        logger.warn("这是warn日志...");
        logger.error("这是error日志...");
    }

}

其他配置

设置日志的级别: logging.level

#修改日志的级别,默认root是info
logging.level.root=trace

指定日志的文件名: logging.file ,会在当前项目下生成springboot.log日志

# 不指定路径在当前项目下生成springboot.log日志
logging.file=springboot.log

# 可以指定完整的路径;
logging.file=d://springboot.log

指定日志的文件的目录: logging.path , 日志文件名称使用SpringBoot默认的输出日志文件名.

# 在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用spring.log 作为默认文件
logging.path=/spring/log

如果同时指定了 logging.file , 则使用 logging.file , 不会使用 logging.path

在这里插入图片描述

指定日志在控制台输出的格式: logging.pattern.console

# 在控制台输出的日志的格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

指定文件中日志输出的格式: logging.pattern.file

# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} ==== %msg%n

日志的输出格式
在这里插入图片描述

6.5.SpringBoot指定日志文件

如果还是不够用的话,可以自定义配置。给类路径下放上每个日志框架自己的配置文件即可;SpringBoot就不使用他默认配置的
在这里插入图片描述

logback.xml示例

logback.xml:直接就被日志框架识别了;

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

 <!-- 日志添加到控制台 -->
 <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
     <encoder>
         <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
     </encoder>
 </appender>

 <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
 <appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
     <file>logs/quickstart.log</file>
     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <fileNamePattern>logs/smt.%d{yyyy-MM-dd}.log</fileNamePattern>
     </rollingPolicy>
     <encoder>
         <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
     </encoder>
 </appender>

 <appender name="businessLogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
     <!-- 按每小时滚动文件,如果一个小时内达到10M也会滚动文件, 滚动文件将会压缩成zip格式 -->
     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <fileNamePattern>logs/smt-%d{yyyy-MM-dd_HH}.%i.zip</fileNamePattern>
         <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
             <maxFileSize>10MB</maxFileSize>
         </timeBasedFileNamingAndTriggeringPolicy>
     </rollingPolicy>
     <!-- 独立的pattern -->
     <encoder>
         <pattern>%d{HH:mm:ss.SSS},%msg%n</pattern>
     </encoder>
 </appender>

 <!-- project default level 本身没有指定appender不打印 传递给上级root-->
 <logger name="com.github.miemiedev.smt" level="DEBUG" />
 <logger name="org.mybatis.spring.SqlSessionFactoryBean" level="DEBUG" />



 <!--log4jdbc -->
 <!-- <logger name="jdbc.sqltiming" level="INFO"/> -->

 <root level="WARN">
     <appender-ref ref="console" />
     <appender-ref ref="rollingFile" />
 </root>
 </configuration>

logback-spring.xml:日志框架就不直接加载日志的配置项,由SpringBoot解析日志配置,可以使用SpringBoot 的高级Profile功能

<!-- 日志添加到控制台 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <springProfile name="dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
            </springProfile>
            <springProfile name="!dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
            </springProfile>
        </layout>
    </appender>
#指定当前模式
spring:
  profiles:
    active: dev

如果使用logback.xml作为日志配置文件,还要使用profile功能,会有以下错误 no applicable action for [springProfile]

6.6.切换日志框架

弃用SpringBoot官方指定的logback日志框架,改用别的日志框架实现。但没太大实际意义,因为logback是最先进的版本,一般没有必要替换。(不推荐,只是教大家如何切换)
在这里插入图片描述
pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <artifactId>logback-classic</artifactId>
            <groupId>ch.qos.logback</groupId>
        </exclusion>
        <exclusion>
            <artifactId>log4j-over-slf4j</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
    </exclusions>
</dependency>

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

在resource目录下添加log4j.properties

### set log levels ###
log4j.rootLogger = debug,stdout,D,E

### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} ===== %5p %c{ 1 }:%L - %m%n

#### 输出到日志文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/log.log
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
#
#### 保存异常信息到单独文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/error.log ## 异常日志文件名
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

切换为log4j2框架

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

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

七、springboot自动化配置原理

## 7.1.前言

在这里插入图片描述
不论在工作中,亦或是求职面试,Spring Boot已经成为我们必知必会的技能项。除了某些老旧的政府项目或金融项目持有观望态度外,如今的各行各业都在飞速的拥抱这个已经不是很新的Spring启动框架。

当然,作为Spring Boot的精髓,自动配置原理的工作过程往往只有在“面试”的时候才能用得上,但是如果在工作中你能够深入的理解Spring Boot的自动配置原理,将无往不利。

Spring Boot的出现,得益于“习惯优于配置”的理念,没有繁琐的配置、难以集成的内容(大多数流行第三方技术都被集成),这是基于Spring 4.x提供的按条件配置Bean的能力。

7.2.SpringBoot的入口

我们开发任何一个Spring Boot项目,都会用到如下的启动类

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

从上面代码可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication.run)最为耀眼,所以要揭开SpringBoot的神秘面纱,我们要从这两位开始就可以了。

7.3.SpringBootApplication背后的秘密

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}

虽然定义使用了多个Annotation进行了原信息标注,但实际上重要的只有三个Annotation:

@Configuration@SpringBootConfiguration点开查看发现里面还是应用了@Configuration@EnableAutoConfiguration
@ComponentScan

所以,如果我们使用如下的SpringBoot启动类,整个SpringBoot应用依然可以与之前的启动类功能对等:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

每次写这3个比较累,所以写一个@SpringBootApplication方便点。接下来分别介绍这3个Annotation。

7.4.@Configuration

这里的@Configuration对我们来说不陌生,它就是JavaConfig形式的Spring Ioc容器的配置类使用的那个@Configuration,SpringBoot社区推荐使用基于JavaConfig的配置形式,所以,这里的启动类标注了@Configuration之后,本身其实也是一个IoC容器的配置类。
举几个简单例子回顾下,XML跟config配置方式的区别:

表达形式层面

基于XML配置的方式是这样:

<?xml version="1.0" encoding="UTF-8"?>
	<beans xmlns="http://www.springframework.org/schema/beans"
	       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
	       default-lazy-init="true">
	    <!--bean定义-->
	</beans>

而基于JavaConfig的配置方式是这样:

@Configuration
public class MockConfiguration{
    //bean定义
}

任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类。

注册bean定义层面

基于XML的配置形式是这样:

<bean id="mockService" class="..MockServiceImpl">
    ...
</bean>

而基于JavaConfig的配置形式是这样的:

@Configuration
public class MockConfiguration{
    @Bean
    public MockService mockService(){
        return new MockServiceImpl();
    }
}

任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。

表达依赖注入关系层面

为了表达bean与bean之间的依赖关系,在XML形式中一般是这样:

<bean id="mockService" class="..MockServiceImpl">
    <propery name ="dependencyService" ref="dependencyService" />
</bean>

<bean id="dependencyService" class="DependencyServiceImpl"></bean>

而基于JavaConfig的配置形式是这样的:

@Configuration
public class MockConfiguration{
    @Bean
    public MockService mockService(){
        return new MockServiceImpl(dependencyService());
    }
    
    @Bean
    public DependencyService dependencyService(){
        return new DependencyServiceImpl();
    }
}

如果一个bean的定义依赖其他bean,则直接调用对应的JavaConfig类中依赖bean的创建方法就可以了。

7.5.@ComponentScan扫描bean

我们原来使用spring的使用不会在xml中一个一个配置bean,我们在再类上加上@Repository@Service,@Controller,@Component,并且注入时可以使用@AutoWired的注解注入。 这一切的功能都需要我们配置包扫描<context:component-scan base-package="com.bruceliu"/>.
然而现在注解驱动开发已经没有了配置文件,不能配置。但是提供了@ComponentScan,我们可以在配置类上面加上这个注解也是一样,并且也能扫描配置包项目的相关注解,也能完成自动注入。

接下来我们先来看扫描组件,后面再看注入

@Service
public class UserService {
    public User getUser(Long id){
        System.out.println("userservice...");
        return null;
    }
}
package com.bruceliu.controller;

import com.bruceliu.bean.User;
import org.springframework.stereotype.Controller;


@Controller
public class UserController {

    //先不拷贝页面,直接打印即可
    public User getUser(Long id){
        System.out.println("usercontroller...");
        return null;
    }
}
//注解类==配置文件
@Configuration //告诉spring这是一个注解类
@ComponentScan("com.bruceliu")
public class MainConfig {

    //相当于在xml中配置了<bean id="" class="com.bruceliu.dao.UserDao"><bean/>
    @Bean("userDao") //指定bean的名字
    public UserDao userDao01(){
        return new UserDaoImpl();
    }
}
public class MainConfigTest {

    @Test
    public void testIoc(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName);
        }
    }

}

注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。

7.6.@EnableAutoConfiguration

@EnableAutoConfiguration作为一个复合Annotation,其自身定义关键信息如下:

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

其中,最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。就像一只“八爪鱼”一样借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!
在这里插入图片描述
而这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。

这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:

在这里插入图片描述

这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(…)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

7.7.自动配置生效

每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

@ConditionalOnBean:当容器里有指定的bean的条件下。
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
@ConditionalOnClass:当类路径下有指定类的条件下。
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。

ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)。
在这里插入图片描述
ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。
在这里插入图片描述
在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。

而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。

可能到目前为止还是有所疑惑,但面试的时候,其实远远不需要回答的这么具体,你只需要这样回答:

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。就像一只“八爪鱼”一样。
在这里插入图片描述@EnableAutoConfiguration自动配置的魔法骑士就变成了:从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

SpringBoot的启动原理基本算是讲完了,为了方便记忆,我根据上面的分析画了张图
在这里插入图片描述

SpringBoot自动化配置关键组件关系图

mybatis-spring-boot-starter、spring-boot-starter-web等组件的META-INF文件下均含有spring.factories文件,自动配置模块中,SpringFactoriesLoader收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的bean。

可以发现其最终实现了ImportSelector(选择器)和BeanClassLoaderAware(bean类加载器中间件),重点关注一下AutoConfigurationImportSelector的selectImports方法。

 public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

该方法在springboot启动流程——bean实例化前被执行,返回要实例化的类信息列表。我们知道,如果获取到类信息,spring自然可以通过类加载器将类加载到jvm中,现在我们已经通过spring-boot的starter依赖方式依赖了我们需要的组件,那么这些组建的类信息在select方法中也是可以被获取到的,不要急我们继续向下分析。

  protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

该方法中的getCandidateConfigurations方法,通过方法注释了解到,其返回一个自动配置类的类名列表,方法调用了loadFactoryNames方法,查看该方法

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

在上面的代码可以看到自动配置器会根据传入的factoryClass.getName()到项目系统路径下所有的spring.factories文件中找到相应的key,从而加载里面的类。我们就选取这个mybatis-spring-boot-autoconfigure下的spring.factories文件
在这里插入图片描述
进入org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration中,主要看一下类头:
在这里插入图片描述
发现Spring的@Configuration,俨然是一个通过注解标注的springBean,继续向下看,

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class})这个注解的意思是:当存在SqlSessionFactory.class, SqlSessionFactoryBean.class这两个类时才解析MybatisAutoConfiguration配置类,否则不解析这一个配置类,make sence,我们需要mybatis为我们返回会话对象,就必须有会话工厂相关类。

@CondtionalOnBean(DataSource.class):只有处理已经被声明为bean的dataSource。

@ConditionalOnMissingBean(MapperFactoryBean.class)这个注解的意思是如果容器中不存在name指定的bean则创建bean注入,否则不执行(该类源码较长,篇幅限制不全粘贴)

以上配置可以保证sqlSessionFactory、sqlSessionTemplate、dataSource等mybatis所需的组件均可被自动配置,@Configuration注解已经提供了Spring的上下文环境,所以以上组件的配置方式与Spring启动时通过mybatis.xml文件进行配置起到一个效果。通过分析我们可以发现,只要一个基于SpringBoot项目的类路径下存在SqlSessionFactory.class, SqlSessionFactoryBean.class,并且容器中已经注册了dataSourceBean,就可以触发自动化配置,意思说我们只要在maven的项目中加入了mybatis所需要的若干依赖,就可以触发自动配置,但引入mybatis原生依赖的话,每集成一个功能都要去修改其自动化配置类,那就得不到开箱即用的效果了。所以Spring-boot为我们提供了统一的starter可以直接配置好相关的类,触发自动配置所需的依赖(mybatis)如下:
在这里插入图片描述
这里是截取的mybatis-spring-boot-starter的源码中pom.xml文件中所有依赖:
在这里插入图片描述

因为maven依赖的传递性,我们只要依赖starter就可以依赖到所有需要自动配置的类,实现开箱即用的功能。也体现出Springboot简化了Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发。

八、springboot重点

8.1 springboot框架日志移除

在这里插入图片描述

8.2 springboot内置的框架

在这里插入图片描述
在这里插入图片描述

8.3 maven的生命周期

在这里插入图片描述

8.4 springboot自动配置流程

在这里插入图片描述

8.5 springboot热启动

在开发过程中,当写完一个功能我们需要运行应用程序测试,可能这个小功能中存在多个小bug,我们需要改正后重启服务器,这无形之中拖慢了开发的速度增加了开发时间,SpringBoot提供了spring-boot-devtools,使我们在更改应用和配置文件的时候,自动重启应用!

8.5.1.打开pom.xml文件添加依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-devtools</artifactId>
   <optional>true</optional>
</dependency>

只要classpath下的文件有变动,它就会自动重启。这在使用IDE时非常有用,因为可以很快得到代码改变的反馈。默认情况下,classpath下任何指向文件夹的实体都会被监控,注意一些资源的修改比如静态assets,视图模板不需要重启应用。

由于DevTools监控classpath下的资源,所以唯一触发重启的方式就是更新classpath。在Eclipse里,保存一个修改的文件将引起classpath更新,并触发重启。在IntelliJ IDEA中,默认是不自动编译的,我们需要设置自动编译。

8.5.2.设置IDEA自动编译:

(1).快捷键Ctrl+Alt+S打开设置,在BuildExecotion,Deployment->Compiler->勾选Build Project automatically在这里插入图片描述

(2).快捷键Ctrl + Shift + Alt + /,选择Registry
在这里插入图片描述
(3).勾选 Compiler autoMake allow when app running
在这里插入图片描述
重启应用,当改动代码时,观察控制台输出,你会发现Spring Boot已经检测到了文件变化,并重新启动,你会发现体验为何如此之棒,爽极了!

九、自定义启动器

为了加深对SpringBoot中自动装配的理解,我们自定义一个starter来实现,具体步骤如下

9.1.自定义starter

9.1.1.IDEA中创建maven项目

在这里插入图片描述
指定项目的坐标信息
在这里插入图片描述
在这里插入图片描述

9.1.2.配置依赖

在pom配置文件中添加如下依赖,增加SpringBoot自身的自动配置作为依赖。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>2.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-configuration-processor</artifactId>
         <version>2.1.4.RELEASE</version>
     </dependency>
</dependencies>

9.1.3.属性配置类

package com.bruceliu.service;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "hello")
public class HelloServiceProperties {

    private static final String MSG = "world";

    private String msg = MSG;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

9.1.4.判断依据类

package com.bruceliu.service;

public class HelloService {

    private String msg;

    public String sayHello(){
        return "Hello "+msg;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

根据此类的存在与否来创建这个类的bean

9.1.4.自动配置类

package com.bruceliu.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(HelloServiceProperties.class)
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix = "hello",name="msg",hasvalue ="enabled",matchIfMissing = true)
public class HelloServiceAutoConfiguration {

    @Autowired
    private HelloServiceProperties helloServiceProperties;

    @Bean
    @ConditionalOnMissingBean(HelloService.class)
    public HelloService helloService(){
        HelloService helloService = new HelloService();
        helloService.setMsg(helloServiceProperties.getMsg());
        return helloService;
    }
}

根据HelloServiceProperties提供的参数,并通过@ConditionalOnClass判断HelloService这个类在类路径中是否存在,且当容器中没有这个Bean的情况下自动配置这个bean。

9.1.5.注册配置

若想自动配置生效,我们需要注册自动配置类,在src/main/resources下新建META-INF/spring.factories,如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.bruceliu.service.HelloServiceAutoConfiguration

如果有多个自动配置,则用“,”隔开。

9.2.使用自定义的starter

9.2.1.创建好SpringBoot项目

创建好一个SpringBoot项目。

9.2.2.引入我们自定义的starter

<dependency>
    <groupId>com.bruce.myhello</groupId>
    <artifactId>spring-boot-starter-myhello</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

9.3.查看引入的具体依赖

在这里插入图片描述

9.4.工具类中使用

@RestController
public class HelloStarterController {
    @Resource
    HelloService helloService;

    @RequestMapping("/")
    public String index(){
        return helloService.sayHello();
    }
}

9.5.启动测试

访问:http://localhost:8082/
在这里插入图片描述
然后我们在application.properties中配置如下内容

hello.msg=SpringBoot

再次启动访问测试结果!

ok~自定义的starter搞定

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值