Spring Boot ~ 从入门到入坑。
文章目录
- Spring Boot ~ 从入门到入坑。
- Spring Boot 概述。
- SpringBoot 项目入门。
- 快速构建 SpringBoot 工程 ~ https://start.spring.io/。
- SpringBoot 起步依赖原理。
- SpringBoot 配置。
- SpringBoot 整合 JUnit。
- SpringBoot 整合 Redis。
- SpringBoot 整合 MyBatis。
- SpringBoot 原理。
- SpringBoot 项目部署。
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)进行配置。
server.port=8080
冒号 :
后有一个空格。(必须)。
缩进:2 个空格。
server:
port: 8080
加载顺序。properties > yml > 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 {
实际开发中导入别人的包,每次还要找包名,太麻烦。
改进。
↓ ↓ ↓
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);
}
}
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
。
ApplicationContextInitializer
和 SpringApplicationRunListener
需要配置才生效。
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