Spring Boot ~ 从入门到入坑。

Spring Boot ~ 从入门到入坑。


文章目录


Spring Boot 概述。

快速构建 Spring 项目。

约定优于配置。

Spring 的顶级项目之一。

Spring: The source for modern java.

  • Spring Boot。
    Build Anything。
  • Spring Cloud。
    Coordinate Anything。
  • Spring Cloud Data Flow。
    Connect Everything。


Spring 缺点。
  • 配置繁琐。
  • 依赖版本繁琐。


SpringBoot 功能。
  • 自动配置。
  • 起步依赖。

Maven 项目对象模型(Project Object Model,POM),定义了对其他库的依赖传递。
简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

  • 辅助功能。

eg. 嵌入式服务器、安全、指标、健康检测、外部配置等。

Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。



SpringBoot 项目入门。

pom.xml
<?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.geek</groupId>
    <artifactId>springBoot-HelloWorld</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- SpringBoot 工程需要继承的父工程。-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
    </parent>

    <dependencies>
        <!-- web 开发的起步依赖。-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>



controller。
package com.geek.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping
    public String hello() {
        return "Hello, Spring Boot,!";
    }
}



引导类。
package com.geek;

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

/**
 * 引导类。SpringBoot 项目的入口。
 */
@SpringBootApplication
public class HelloApplication {

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

启动后,日志。

在这里插入图片描述

访问。

浏览器:http://localhost:8080/

在这里插入图片描述



小结。
  • SpringBoot 在创建项目时,使用 jar 的打包方式。(没有指定 <packaging></packaging> 默认为 jar)。

  • SpringBoot 的引导类,是项目的入口。运行 main(); 方法就可以启动项目。

  • 使用 SpringBoot 和 Spring 构建的项目,业务代码编写的方式完全一样。



快速构建 SpringBoot 工程 ~ https://start.spring.io/。

IDEA 已经集成此功能。

可以勾选自动集成的功能。



SpringBoot 起步依赖原理。

spring-boot-starter-parent。
  • 定义了各种技术的版本信息,组合了一套最优的搭配的技术版本。
  • 在各种 starter 中,定义了完成该功能需要的坐标集合,其中大部分信息来自于父工程。
  • 我们的工程继承了 parent,引入 starter 以后,通过依赖传递,就可憎简单方便的获取需要的 jar 包,并且不会存在版本冲突等问题。
  • ta 的 parent。
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
  </parent>
  • parent 的 parent。
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.2.5.RELEASE</version>
  <packaging>pom</packaging>
  <name>Spring Boot Dependencies</name>
  <description>Spring Boot Dependencies</description>
  <url>https://projects.spring.io/spring-boot/#</url>
spring-boot-starter-web。


SpringBoot 配置。

配置文件分类。

SpringBoot 是基于约定的,所以很多配置都有默认值,但如果想使自己的配置替换默认配置,就可以使用 applicatin.properties 或 application.yaml(application.yml)进行配置。

  • properties。
server.port=8080
  • yml。

冒号 : 后有一个空格。(必须)。

缩进:2 个空格。

server:
  port: 8080
  • yaml。


加载顺序。properties > yml > yaml。


  • yaml。

YAML ——> YAML Ain’t Markup Language。YAML 是一种能够直观的被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持 YAML 库的不同编程语言程序导入。eg. C / C++, Ruby, Python, Java, Perl, C#, PHP 等。YML 文件是以数据为核心的,比传统的 xml 方式更简洁。

  • properties。

层级结构不直观。

server.port=8080
server.address=127.0.0.1
  • xml

标签繁琐。

<server>
	<port>8080</port>
	<address>127.0.0.1</address>
</server>
  • yml。

简洁,以数据为核心。

server:
  port: 8080
  address: 127.0.0.1


yaml 基本语法。
  • 大小写敏感。
  • 数据值前必须有空格,作为分隔符。
  • 使用缩进表示层级关系。
  • 缩进时不允许使用 Tab 键,只允许使用空格(各系统 Tab 对应的空格不同,导致层次混乱)。
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。
  • # 表示注释,从这个字符一直到行尾,都会被解析器忽略。


yaml 数据格式。
- 对象(map) ~ 键值对的集合。
person:
  name: geek
# 行内写法。用的不多。
person: {name: geek}
- 数组 ~ 一组按次序排列的值。
address:
  - beijing
  - shanghai
# 行内写法。
adress: [beijing,shanghai]
- 纯量 ~ 单个的、不再可分的值。
# 单引忽略转义字符。
msg1: 'hello \n world'
# 双引识别转义字符。
msg2: 'hello \n world'
- 参数引用。
name: abc

# 参数引用。
person01:
  name:${name}


读取配置文件。
- @Value
package com.geek.springboot_quick.controller;

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

@RestController
public class HelloController {

    @Value("${name}")// 和配置文件一致。
    private String name;// 随意。

    // 对象注入。
    @Value("${person.name}")
    private String name2;

    @Value("${person.age}")
    private int age;

    // 数组注入。
    @Value("${address[0]}")
    private String address;

    // 常量。
    @Value("${msg1}")
    private String msg1;

    @Value("${msg2}")
    private String msg2;

    @RequestMapping("/hello2")
    public void hello02() {
        System.out.println(name);
        System.out.println("name2 = " - name2);
        System.out.println("age = " - age);
        System.out.println("address = " - address);
        System.out.println("msg1 = " - msg1);
        System.out.println("msg2 = " - msg2);
    }

    @RequestMapping("/hello")
    public String hello() {
        return "Hello Spring Boot 222.";
    }

}

- Environment

对比 @Value ——> 只需注入一个对象。

    @Autowired
    private Environment environment;
System.out.println(environment.getProperty("person.name"));
- @ConfigurationProperties

给 Bean 对象(domain)的属性注入。

@Component
@ConfigurationProperties
public class Person {

    private String name;
    private int age;

setter...
getter...

toString...

}

controller 层使用。

    @Autowired
    private Person person;

    @RequestMapping("/hello3")
    public void hello03() {

        System.out.println(person);
    }

age 为 0,说明使用了配置文件中的 name: abc。

name: abc

person:
  name: geek
  age: 25

而没有使用 person 中的 name。(外层没有指定 age,默认为 0)。

Person{name='abc', age=0}

所以要在 @ConfigurationProperties 后指定前缀,
@ConfigurationProperties(prefix = “person”)
以使用 person 中的 name。

@Component
@ConfigurationProperties(prefix = "person")
public class Person {
person:
  name: geek
  age: 25
Person{name='geek', age=25}


@ConfigurationProperties 还可以给 bean 注入数组。
person:
  name: geek
  age: 25
  address:
    - beijing
    - shanghai
    - wuhan
@Component
@ConfigurationProperties(prefix = "person")
public class Person {

    private String name;
    private int age;
    private String[] address;

getter...
setter...
toString...

controller。


    @Autowired
    private Person person;

    @RequestMapping("/hello3")
    public void hello03() {

        System.out.println(person);

        String[] address = person.getAddress();
        for (String s : address) {
            System.out.println("s = " + s);
        }
    }
Person{name='geek', age=25, address=[beijing, shanghai, wuhan]}
s = beijing
s = shanghai
s = wuhan


profile。

我们在开发 Spring Boot 应用时,通常同一套程序会被安装到不同的环境中,eg. 开发、测试、生产等。其中数据库的地址、服务器端口等等配置都不同。如果每次打包都要修改配置文件,非常麻烦。profile 就是用来进行动态配置切换的。

- 配置文件。
profile 配置方式。
- 多 properties 文件方式。

在这里插入图片描述

  • 文件名固定格式。

application-名称.properties

启动程序,如果不指定使用哪一个,会提示,并使用 SpringBoot 内置默认配置。

INFO 17022 — [ main] c.g.s.SpringbootProfilesApplication : No active profile set, falling back to default profiles: default

  • 激活。

在主配置文件中:application.properties,指定。

spring.profiles.active=dev

INFO 17549 — [ main] c.g.s.SpringbootProfilesApplication : The following profiles are active: dev

- 多 yml 文件方式。
- yml 多文档方式。
  • 同一个 application.yml 文件中。
  • 使用 --- 分隔。
server:
  port: 8080

spring:
  profiles: pro

---

server:
  port: 8082

spring:
  profiles: test

---

server:
  port: 8081

spring:
  profiles: dev

---

spring:
  profiles:
    active: dev

同样需要指定激活哪一个。



profile 激活方式。
spring.profiles.active=dev

spring:
  profiles:
    active: dev


- 虚拟机参数 ~ VM options。
  • VM options。

-Dspring.profiles.active=test

在这里插入图片描述



- 命令行参数 ~ Program arguments。
  • Program arguments。

–spring.profiles.active=test

在这里插入图片描述



Tips:生产环境的运行。

生产环境一般没有 IDEA。

Spring Boot 可以将项目打包成 jar 独立运行。

geek@geek-PC:~/IdeaProjects/SpringBoot_empty/springboot_profiles/target$ java -jar springboot_profiles-0.0.1-SNAPSHOT.jar 
  • 使用命令行指定参数。

geek@geek-PC:~/IdeaProjects/SpringBoot_empty/springboot_profiles/target$ java -jar springboot_profiles-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev



内部配置加载顺序。

Spring Boot 启动时,会从以下位置加载配置文件。

  • file:./config/ ——> 当前项目下的 /config 目录。
  • file:./ ——> 当前项目的根目录。
  • classpath:/config/ ——> classpath 的 /config 目录。
  • classpath:/ ——> classpath 的根目录。

加载顺序 ↓。
优先级 ↓。(优先上面)。

  • classpath。

在这里插入图片描述

  • project。

在这里插入图片描述

在这里插入图片描述



外部配置加载顺序。

17 种外部配置方式。

https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/spring-boot-features.html#boot-features-external-config

  • Command line arguments.(No. 4)。

测试。

使用 jar 包,命令行。

geek@geek-PC:~/IdeaProjects/SpringBoot_empty/springboot_config/target$ java -jar ./springboot_config-0.0.1-SNAPSHOT.jar

这时会使用

因为 ① 和 ② 并不在 classpath 中,就不会被打进 jar 包。

在这里插入图片描述

  • 可以使用命令行指定端口号(优先读取)。

geek@geek-PC:~/IdeaProjects/SpringBoot_empty/springboot_config/target$ java -jar ./springboot_config-0.0.1-SNAPSHOT.jar --server.port=8082

–server.servlet.context-path=/hehe



使用 spring.config.location 指定外部配置文件。
外部配置。

使用 java -jar 命令时,如不指定配置文件,同样也适用 file 的优先级规则,且自动使用这些配置。

  • file:./config/ ——> 当前项目下的 /config 目录。
  • file:./ ——> 当前项目的根目录。


小结。

外部配置和内部配置形成互补。

一般使用外部配置增加额外的配置信息。

(优先使用外部配置。当外部配置文件中没有内部配置的参数时,内部配置特有的参数还是会生效)。



SpringBoot 整合 JUnit。

  • 创建工程。pom 引入。

  • 如果使用了快速构建,需要手动加入 JUnit 依赖。

  • 并且,将 <exclusions></exclusions> 删除。否则会报错。

在这里插入图片描述

            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
<?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 https://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.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.geek</groupId>
    <artifactId>springboot_test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot_test</name>
    <description>Demo project for Spring Boot</description>

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

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

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

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

</project>

创建 Service。

package com.geek.springboot_test.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public void add() {
        System.out.println("add...");
    }
}

测试类。(可以 Alt - Insert 自动生成)。

package com.geek.springboot_test.service;

import com.geek.springboot_test.SpringbootTestApplication;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * UserService 的测试类。
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootTestApplication.class)
class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    void add() {
        userService.add();
    }
}



SpringBoot 整合 Redis。

  • 依赖。
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

测试代码。

package com.geek.springboot_redis;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class SpringbootRedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
    }

    @Test
    public void testSet() {
        // 存入数据。
        redisTemplate.boundValueOps("name").set("geek");
    }

    @Test
    public void testGet() {
        Object name = redisTemplate.boundValueOps("name").get();
        System.out.println("name = " - name);
    }
}

如果是本机 Redis,则不需要任何配置,使用默认。

如果不是本机,在 application.yml 中配置。

spring:
  redis:
    host: 192.168.223.128 # Redis 主机 IP。
    port: 6379  # 默认。


SpringBoot 整合 MyBatis。

注解。

pom依赖。

<!-- 注意这里是 mybatis 开头。
因为这是 MyBatis 提供的,而不是 SpringBoot。
-->
		<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

domain。

package com.geek.springboot_mybatis.domain;

import java.io.Serializable;

public class User implements Serializable {

    private int id;
    private String username;
    private String password;

setter...
getter...

toString

application.yml

spring:
  datasource:
    url: jdbc:mysql://192.168.223.128//springboot_geek
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

Interface Mapper。

package com.geek.springboot_mybatis.mapper;

import com.geek.springboot_mybatis.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("select * from t_user")
    public List<User> findALl();
}

测试类。

package com.geek.springboot_mybatis;

import com.geek.springboot_mybatis.domain.User;
import com.geek.springboot_mybatis.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class SpringbootMybatisApplicationTests {

    @Autowired
    private UserMapper userMapper;
    // 红色警告,看着不爽,可以在 UserMapper 上添加 @Repository。

    @Test
    public void testSelect() {
        List<User> userList = userMapper.findALl();
        System.out.println(userList);
    }

    @Test
    void contextLoads() {
    }

}



xml。

接口。

package com.geek.springboot_mybatis.mapper;

import com.geek.springboot_mybatis.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
@Repository
public interface UserXmlMapper {

    List<User> findAll();
}

yml。

spring:
  datasource:
    url: jdbc:mysql://192.168.223.128/springboot_geek
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml  # mapper 的映射文件路径。
  type-aliases-package: com.geek.springboot_mybatis.domain
#  config-location:  # 指定 MyBatis 的核心配置文件。

*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="com.geek.springboot_mybatis.mapper.UserXmlMapper"><!-- 接口全限定名。-->

    <!-- 查询所有。-->
    <select id="findAll" resultType="user">
        select * from t_user
    </select>
    
</mapper>

测试类。

package com.geek.springboot_mybatis;

import com.geek.springboot_mybatis.domain.User;
import com.geek.springboot_mybatis.mapper.UserMapper;
import com.geek.springboot_mybatis.mapper.UserXmlMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class SpringbootMybatisApplicationTests {

    @Autowired
    private UserMapper userMapper;
    // 红色警告,看着不爽,可以在 UserMapper 上添加 @Repository。

    @Autowired
    private UserXmlMapper userXmlMapper;

    @Test
    public void testXML() {
        List<User> userList = userXmlMapper.findAll();
        System.out.println(userList);
    }

    @Test
    public void testSelect() {
        List<User> userList = userMapper.findAll();
        System.out.println(userList);
    }

    @Test
    void contextLoads() {
    }

}



SpringBoot 原理。

SpringBoot 自动配置。
Condition。

Condition 是在 Spring 4.0 增加的条件判断功能,通过 ta 可以实现选择性地创建 Bean 操作。

事实上,
SpringApplication.run(SpringbootConditionApplication.class, args);
返回了一个
ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringbootConditionApplication.class, args);
对象。

package com.geek.springboot_condition;

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

@SpringBootApplication
public class SpringbootConditionApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringbootConditionApplication.class, args);

        // 获取 Bean,RedisTemplate。
        Object redisTemplate = applicationContext.getBean("redisTemplate");
        System.out.println("redisTemplate = " - redisTemplate);
    }

}

  • @Condition 的使用。

启动类。

package com.geek.springboot_condition;

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

@SpringBootApplication
public class SpringbootConditionApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringbootConditionApplication.class, args);

        // 获取 Bean,RedisTemplate。
//        Object redisTemplate = applicationContext.getBean("redisTemplate");
//        System.out.println("redisTemplate = " - redisTemplate);

        Object user = applicationContext.getBean("user");
        System.out.println("user = " - user);
    }

}

User 类。

package com.geek.springboot_condition.domain;

public class User {
}

配置类。

package com.geek.springboot_condition.config;

import com.geek.springboot_condition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {

    @Bean
    public User user() {
        return new User();
    }
}

运行,可以从 Spring 容器中拿到 User 对象。

- 需求:导入 Redis 包后创建 User 对象,否则不创建。

导入 Redis 包后创建 User 对象,否则不创建。

package com.geek.springboot_condition.config;

import com.geek.springboot_condition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {

    @Conditional()
    @Bean
    public User user() {
        return new User();
    }

}

在这里插入图片描述

在这里插入图片描述

追踪 @Conditional。——>

参数需要一个实现条件接口 Interface Condition 实现类。

matches(); 方法,返回一个 boolean。

废话不说 ——> 做! ~

package com.geek.springboot_condition.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ClassCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return false;
    }

}

class User 上 @Conditional(ClassCondition.class)

package com.geek.springboot_condition.config;

import com.geek.springboot_condition.condition.ClassCondition;
import com.geek.springboot_condition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {

    @Conditional(ClassCondition.class)
    @Bean
    public User user() {
        return new User();
    }
}

此时方法返回的是 false。

所以不创建。

return true; ——> 则创建 User 对象。


  • 需求:导入 Redis 坐标后创建 User Bean。
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
package com.geek.springboot_condition.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
//        return false;
//        return true;

        // 需求:导入 Redis 坐标后创建 User Bean。

        boolean flag = true;

        try {
            Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
            flag = false;
        }

        return flag;

    }
}



- 改进:判断任意类(动态指定)后创建 bean。
  • 创建一个注解类。
package com.geek.springboot_condition.condition;

import org.springframework.context.annotation.Conditional;

@Conditional(ClassCondition.class)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConditionOnClass {

    String[] value();
}

自己的配置类。

package com.geek.springboot_condition.config;

import com.geek.springboot_condition.condition.ConditionOnClass;
import com.geek.springboot_condition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {

    // 将此注解放到自己自定义的注解上。
    //    @Conditional(ClassCondition.class)
    @Bean
    // 使用自己的注解。
    @ConditionOnClass("redis.clients.jedis.Jedis")
    public User user() {
        return new User();
    }
}

需求:导入通过注解属性值指定的类。
  • 先看看关于注解的参数。

在这里插入图片描述

package com.geek.springboot_condition.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

import java.util.Map;

public class ClassCondition implements Condition {
    /**
     * @param conditionContext      上下文。用于获取环境、IoC 容器,ClassLoader 对象。
     * @param annotatedTypeMetadata 注解元对象。获取注解定义的属性值。
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        // 获取注解属性值。
        Map<String, Object> annotationAttributes = annotatedTypeMetadata.getAnnotationAttributes(ConditionOnClass.class.getName());
//        System.out.println("~ ~ ~ ~ ~ ~ ~");
//        System.out.println(annotationAttributes);
//        System.out.println("~ ~ ~ ~ ~ ~ ~");

        // 需求2:判断任意类(动态指定)后创建 bean。导入通过注解属性值 value 指定的类。
        String[] value = (String[]) annotationAttributes.get("value");

        boolean flag = true;

        try {

            for (String className : value) {
                Class<?> aClass = Class.forName(className);
            }

        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
            flag = false;
        }

        return flag;

        // 需求:导入 Redis 坐标后创建 User Bean。
/*
        boolean flag = true;

        try {
            Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
            flag = false;
        }

        return flag;
*/

    }
}

得出 SpringBoot 自动创建 Bean 的原理。

如果坐标中导入了 ...starter,SpringBoot 就会帮你创建这个 Bean。



~ ~ ~


SpringBoot 内置 Web 服务器 ~ 4 种 ~ 默认 Tomcat。

SpringBoot 默认使用 Tomcat 作为内置服务器。
SpringBoot 提供了 4 种服务器。

在这里插入图片描述

来看 class class EmbeddedWebServerFactoryCustomizerAutoConfiguration

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication
@EnableConfigurationProperties({ServerProperties.class})
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
    public EmbeddedWebServerFactoryCustomizerAutoConfiguration() {
    }


    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class})
    public static class TomcatWebServerFactoryCustomizerConfiguration {
        public TomcatWebServerFactoryCustomizerConfiguration() {
        }

}

当有 @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class}) Tomcat 的相关依赖时,SpringBoot 就会启动 Tomcat 服务器。

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


切换内置服务器。

将 Tomcat 依赖排除。

引入 netty 依赖。

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


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

ok

在这里插入图片描述



~ ~ ~


@Enable* 注解。

SpringBoot 中提供了很多 Enable 开头的注解,这些注解都是用于动态启动某些功能的。而其底层原理是使用了 @Import 注解导入一些配置类,实现 Bean 的动态加载。



SpringBoot 工程是否可以直接获取 jar 包中定义的 Bean?
- 实验。

创建一个模块,springboot_enable_other。

在这个模块中创建一个 User 类。

UserConfig 类。

package com.geek.springboot_enable_other.config;

import com.geek.springboot_enable_other.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {

    @Bean
    public User getUser() {
        return new User();
    }
}

其他什么也不干。



  • 再创建一个模块,springboot_enable。

依赖 springboot_enable_other。

        <dependency>
            <groupId>com.geek</groupId>
            <artifactId>springboot_enable_other</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

试图获取 User 对象。

package com.geek.springboot_enable;

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

@SpringBootApplication
public class SpringbootEnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);

        Object user = context.getBean("user");
        System.out.println("user = " - user);
    }

}

不能直接获取。

  • 原因。

@ComponentScan 扫描范围:

当前引导类所在包及其子包。

解决方法 1。

@ComponentScan(“com.geek.springboot_enable_other.config”)
package com.geek.springboot_enable;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;


/**
 * @ComponentScan 扫描范围。
 * <p>
 * 当前引导类所在包及其子包。
 * <p>
 * package com.geek.springboot_enable;
 * com.geek.springboot_enable_other.config
 */
@ComponentScan("com.geek.springboot_enable_other.config")
@SpringBootApplication
//@Import(UserConfig.class)
public class SpringbootEnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);

        Object user = context.getBean("user");
        System.out.println("user = " - user);
    }

}

@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

实际开发中导入别人的包,每次还要找包名,太麻烦。

改进。

↓ ↓ ↓

  • 使用 @Import 注解。加载类,Spring 会创建并放入容器。
package com.geek.springboot_enable;

import com.geek.springboot_enable_other.config.UserConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;


/**
 * @ComponentScan 扫描范围。
 * <p>
 * 当前引导类所在包及其子包。
 * <p>
 * package com.geek.springboot_enable;
 * com.geek.springboot_enable_other.config
 */
//@ComponentScan("com.geek.springboot_enable_other.config")
@SpringBootApplication
@Import(UserConfig.class)
public class SpringbootEnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);

        Object user = context.getBean("user");
        System.out.println("user = " - user);
    }

}

  • 对 @Enable 封装。
package com.geek.springboot_enable_other.config;

import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}

package com.geek.springboot_enable;

import com.geek.springboot_enable_other.config.EnableUser;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;


/**
 * @ComponentScan 扫描范围。
 * <p>
 * 当前引导类所在包及其子包。
 * <p>
 * package com.geek.springboot_enable;
 * com.geek.springboot_enable_other.config
 * <p>
 * 2. 使用 @Import 注解。
 * <p>
 * 3. 对 @Import 进行封装。
 */
//@ComponentScan("com.geek.springboot_enable_other.config")
@SpringBootApplication
//@Import(UserConfig.class)
@EnableUser
public class SpringbootEnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);

        Object user = context.getBean("user");
        System.out.println("user = " - user);
    }

}



SpringBoot 自动配置小结。
@EnableAutoConfiguration。

追溯源码流程。

在这里插入图片描述


    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());
        }
    }

AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);

↓↓↓

List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

↓↓↓

    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;
    }

关键文件。

META-INF/spring.factories

在这里插入图片描述



  • @EnableAutoConfiguration 注解内部使用 @Import(AutoConfigurationSelector.class) 来加载配置类。
  • 配置文件位置:META-INF/spring.properties,该配置文件定义了大量的配置类,当 SpringBoot 应用启动时,会自动加载和谐配置类,初始化 Bean。
  • 并不是所有的 Bean 都会被初始化,在配置类中使用 Condition 满足条件的 Bean。


~ ~ ~


自定义 starter。
  • 需求。

自定义 redis-starter。要求当导入 redis 坐标时,SpringBoot 自动创建 Jedis 的 Bean。

参照 MyBatis 的 starter。

SpringBoot 官方并没有给 MyBatis 提供 starter。所以 MyBatis 公司就自己写了一个和 SpringBoot 整合的功能。

<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

现在开始 。

  • 自定义 redis-starter。

  • 创建 redis-spring-boot-autoconfigure 模块。

  • 创建 redis-spring-boot-starter 模块,依赖 redis-spring-boot-autoconfigure 模块。

  • 在 redis-spring-boot-autoconfigure 模块中初始化 Jedis 的 Bean,并定义 META-INF/spring.factories 文件。

  • 在测试模块中引入自定义的 redis-starter 依赖,测试获取 Jedis 的 Bean,操作 redis。

pom.xml

<?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 https://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.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.geek</groupId>
    <artifactId>redis-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis-spring-boot-starter</name>
    <description>Demo project for Spring Boot</description>

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

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

        <!-- 引入 configuration。-->
        <dependency>
            <groupId>com.geek</groupId>
            <artifactId>redis-spring-boot-autoconfigure</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

    </dependencies>
    <!--        <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>

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

</project>

<?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 https://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.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.geek</groupId>
    <artifactId>redis-spring-boot-autoconfigure</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis-spring-boot-autoconfigure</name>
    <description>Demo project for Spring Boot</description>

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

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

        <!-- 引入 Jedis 依赖。-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

        <!--        <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-test</artifactId>
                    <scope>test</scope>
                    <exclusions>
                        <exclusion>
                            <groupId>org.junit.vintage</groupId>
                            <artifactId>junit-vintage-engine</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>-->
    </dependencies>
    <!--

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

</project>

  • <artifactId>redis-spring-boot-autoconfigure</artifactId> 中。
package com.geek.redispringbootautoconfigure;

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

@ConfigurationProperties(prefix = "redis")
public class RedisProperties {

    private String host = "localhost";
    private int port = 6379;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }
}

package com.geek.redispringbootautoconfigure;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;

@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {

    /**
     * 提供 Jedis 的 Bean。
     *
     * @return
     */
    public Jedis jedis(RedisProperties redisProperties) {
//        return new Jedis("192.168.223.129", 6379);
//        return new Jedis(redisProperties.getHost(), redisProperties.getPort());
        return new Jedis("192.168.223.129", redisProperties.getPort());
    }
}

package com.geek.redispringbootautoconfigure;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties(RedisProperties.class)
public class RedisSpringBootAutoconfigureApplication {

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

}

  • META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.geek.redispringbootautoconfigure.RedisAutoConfiguration

  • 测试项目中引入依赖。
        <!-- 自定义 Redis 的 starter。-->
        <dependency>
            <groupId>com.geek</groupId>
            <artifactId>redis-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
package com.geek.springboot_enable;

import com.geek.springboot_enable_other.config.EnableUser;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import redis.clients.jedis.Jedis;


@SpringBootApplication
public class SpringbootEnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);

        Jedis jedis = context.getBean(Jedis.class);
        System.out.println("jedis = " - jedis);

    }

}



SpringBoot 监听机制。
Java 监听机制。

SpringBoot 的监听机制,实际是对 Java 提供的事件监听机制的封装。

  • Java 中的事件监听机制定义了以下几个角色。
  • 事件:Event,继承 java.util.EventObject 类的对象。
  • 事件源:Source,任意对象 Object。
  • 监听器:Listener,实现 java.util.EventListener 接口的对象。


SpringBoot 监听机制。

SpringBoot 在项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口, 项目启动时完成一些操作。

  • ApplicationContextInitializer
  • SpringApplicationRunListener
  • CommandLineRunner
  • ApplicationRunner

定义自己的监听器,实现以上接口,重写方法。在类上加注解 @Component

启动项目。

ApplicationRunner...run();...
CommandLineRunner...run();...
使用:缓存、获取 args。

在这里插入图片描述

package com.geek.springbootlistener.listener;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner...run...");

        System.out.println("args = " - Arrays.asList(args.getSourceArgs()));
    }
}

  • 配置 META-INF/spring.factories

ApplicationContextInitializerSpringApplicationRunListener 需要配置才生效。

org.springframework.context.ApplicationContextInitializer=com.geek.springbootlistener.listener.MyApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=com.geek.springbootlistener.listener.MySpringApplicationRunListener


SpringBoot 启动流程图分析。


SpringBoot 监控 ~ Actuator。

SpringBoot 自带监控功能 Actuator。可以帮助实现对程序内部运行情况的监控。eg. 监控状态、Bean 加载情况、配置属性、日志信息等。

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

INFO 29172 — [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path ‘/actuator’

  • 访问 localhost:8080/actuator。

返回 Json。

       
{
    "_links":{
        "self":{
            "href":"http://localhost:8080/actuator",
            "templated":false
        },
        "health":{
            "href":"http://localhost:8080/actuator/health",
            "templated":false
        },
        "health-path":{
            "href":"http://localhost:8080/actuator/health/{*path}",
            "templated":true
        },
        "info":{
            "href":"http://localhost:8080/actuator/info",
            "templated":false
        }
    }
}

其中,info 中内容为配置文件中,的值。

info.name=zhangsan
info.age=23
{"name":"zhangsan","age":"23"}

health 中的内容。

{"status":"UP"}
  • 配置显示详细信息。
info.name=zhangsan
info.age=23
# 开启健康查检的完整信息。
management.endpoint.health.show-details=always

{
    "status":"UP",
    "components":{
        "diskSpace":{
            "status":"UP",
            "details":{
                "total":54231687168,
                "free":4450590720,
                "threshold":10485760
            }
        },
        "ping":{
            "status":"UP"
        }
    }
}

磁盘信息。

还可以显示 Redis、MySQL 信息。

       
{
    "status":"DOWN",
    "components":{
        "diskSpace":{
            "status":"UP",
            "details":{
                "total":54231687168,
                "free":4448309248,
                "threshold":10485760
            }
        },
        "ping":{
            "status":"UP"
        },
        "redis":{
            "status":"DOWN",
            "details":{
                "error":"org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379"
            }
        }
    }
}
{
    "status":"UP",
    "components":{
        "diskSpace":{
            "status":"UP",
            "details":{
                "total":54231687168,
                "free":4451545088,
                "threshold":10485760
            }
        },
        "ping":{
            "status":"UP"
        },
        "redis":{
            "status":"UP",
            "details":{
                "version":"4.0.11"
            }
        }
    }
}
  • 监控所有。
info.name=zhangsan
info.age=23
# 开启健康查检的完整信息。
management.endpoint.health.show-details=always
spring.redis.host=192.168.223.129
# 将所有监控 endpoints 暴露。
management.endpoints.web.exposure.include=*

http://localhost:8080/actuator

{
    "_links":{
        "self":{
            "href":"http://localhost:8080/actuator",
            "templated":false
        },
        "beans":{
            "href":"http://localhost:8080/actuator/beans",
            "templated":false
        },
        "caches-cache":{
            "href":"http://localhost:8080/actuator/caches/{cache}",
            "templated":true
        },
        "caches":{
            "href":"http://localhost:8080/actuator/caches",
            "templated":false
        },
        "health":{
            "href":"http://localhost:8080/actuator/health",
            "templated":false
        },
        "health-path":{
            "href":"http://localhost:8080/actuator/health/{*path}",
            "templated":true
        },
        "info":{
            "href":"http://localhost:8080/actuator/info",
            "templated":false
        },
        "conditions":{
            "href":"http://localhost:8080/actuator/conditions",
            "templated":false
        },
        "configprops":{
            "href":"http://localhost:8080/actuator/configprops",
            "templated":false
        },
        "env-toMatch":{
            "href":"http://localhost:8080/actuator/env/{toMatch}",
            "templated":true
        },
        "env":{
            "href":"http://localhost:8080/actuator/env",
            "templated":false
        },
        "loggers":{
            "href":"http://localhost:8080/actuator/loggers",
            "templated":false
        },
        "loggers-name":{
            "href":"http://localhost:8080/actuator/loggers/{name}",
            "templated":true
        },
        "heapdump":{
            "href":"http://localhost:8080/actuator/heapdump",
            "templated":false
        },
        "threaddump":{
            "href":"http://localhost:8080/actuator/threaddump",
            "templated":false
        },
        "metrics-requiredMetricName":{
            "href":"http://localhost:8080/actuator/metrics/{requiredMetricName}",
            "templated":true
        },
        "metrics":{
            "href":"http://localhost:8080/actuator/metrics",
            "templated":false
        },
        "scheduledtasks":{
            "href":"http://localhost:8080/actuator/scheduledtasks",
            "templated":false
        },
        "mappings":{
            "href":"http://localhost:8080/actuator/mappings",
            "templated":false
        }
    }
}


SpringBoot 监控 ~ Spring Boot Admin。
  • Spring Boot Admin 是一个开源社区项目,用于管理和监控 SpringBoot 应用程序。

  • Spring Boot Admin 有两个角色。客户端(Client)和服务端(Server)。

  • 应用程序作为 Spring Boot Admin Client 向 Spring Boot Admin Server 注册。

  • Spring Boot Admin Server 的 UI 界面将 Spring Boot Admin Client 的 Actuator Endpoint 上的一些监控信息显示。

使用。
  • admin-server。
  • 创建 admin-server 模块。
  • 导入依赖坐标 admin-starter-server。
  • 在引导类上启用监控功能 @EnableAdminServer。
  • admin-client。
  • 创建 admin-client 模块。
  • 导入依赖坐标 admin-starter-client。
  • 配置相关信息:server 地址等。
  • 启动 server 和 client 服务,访问 server。
		<dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-server</artifactId>
        </dependency>

        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
package com.geek.springboot_admin_server;

import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableAdminServer
@SpringBootApplication
public class SpringbootAdminServerApplication {

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

}

  • server 启动类加注解。
package com.geek.springboot_admin_server;

import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableAdminServer
@SpringBootApplication
public class SpringbootAdminServerApplication {

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

}

  • client 配置。
spring.boot.admin.client.url=http://localhost:9000

management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=*

在这里插入图片描述



SpringBoot 项目部署。

SpringBoot 项目开发完毕,支持两种方式部署到服务器。

  • jar 包(官方推荐)。
  • war 包。
jar 包。

如果不指定 <packaging>,默认打 jar

这个 jar 包可以单独运行。

geek@geek-PC:~$ cd /home/geek/IdeaProjects/SpringBoot_empty/springboot_deploy/target/
geek@geek-PC:~/IdeaProjects/SpringBoot_empty/springboot_deploy/target$ ls
classes                 maven-status
generated-sources       springboot_deploy-0.0.1-SNAPSHOT.jar
generated-test-sources  springboot_deploy-0.0.1-SNAPSHOT.jar.original
maven-archiver          test-classes
geek@geek-PC:~/IdeaProjects/SpringBoot_empty/springboot_deploy/target$ java -jar springboot_deploy-0.0.1-SNAPSHOT.jar 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.5.RELEASE)




war 包。

pom.xml 中指定 war。

    <packaging>war</packaging>
  • 启动类 extends SpringBootServletInitializer{}。
  • 重写方法 protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {。
package com.geek.springboot_deploy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class SpringbootDeployApplication extends SpringBootServletInitializer {

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

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
//        return super.configure(builder);
        return builder.sources(SpringbootDeployApplication.class);
    }

}

geek@geek-PC:~/IdeaProjects/SpringBoot_empty/springboot_deploy/target$ ls
classes                 maven-archiver                    springboot_deploy-0.0.1-SNAPSHOT.jar           springboot_deploy-0.0.1-SNAPSHOT.war.original
generated-sources       maven-status                      springboot_deploy-0.0.1-SNAPSHOT.jar.original  test-classes
generated-test-sources  springboot_deploy-0.0.1-SNAPSHOT  springboot_deploy-0.0.1-SNAPSHOT.war

把 war 包放到 Tomcat 的 webapps 目录下,直接启动 Tomcat,ta 会被自动解压为文件夹。

此时访问要加一层目录。

http://localhost:8080/文件夹名/user/findAll

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lyfGeek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值