SpringBoot

一、SpringBoot 概述

SpringBoot 概念 SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻 辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度上缩短了项目周期。

1.1、Spring 缺点

  • 配置繁琐
    虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。

  • 依赖繁琐
    项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导 入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发 进度。

1.2、SpringBoot 功能

  • 自动配置
    Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定 Spring配置应该用哪个,不该用哪个。该过程是SpringBoot自动完成的。

  • 起步依赖/依赖传递
    起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

  • 辅助功能
    提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。 Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。

二、SpringBoot 配置

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

配置文件分类

  • properties
  • yml/yaml

默认配置文件名称:application
在同一级目录下优先级为:properties > yml > yaml
不同配置文件中相同配置按照加载优先级相互覆盖,不同配置文件中不同配置全部保留

2.1、yaml基本语法

YAML(YAML Ain’t Markup Language),一种数据序列化格式

优点:

  • 容易阅读
  • 容易与脚本语言交互
  • 以数据为核心,重数据轻格式

YAML文件扩展名

  • .yml(主流)
  • .yaml

2.2、yaml语法规则

  • 大小写敏感
  • 属性层级关系使用多行描述,每行结尾使用冒号结束
  • 使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)
  • 属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)
  • # 表示注释
  • 核心规则:数据前面要加空格与冒号隔开

2.2.1、字面值表示方式

## TRUE, True, true, FALSE, False, false均可
boolean: TRUE

## 3.14e+5 支持科学计数法
float: 3.14

## 支持二进制、八进制、十六进制
int: 123

## 使用~表示null
null: ~

## 字符串可以直接书写
string: Java666

## 可以使用双引号包裹特殊字符
string2: "Hello World"

## 日期必须使用yyyy-MM-dd格式
date: 2021-12-17

## 时间和日期之间使用T连接,最后使用+代表时区
datetime: 2021-11-17T14:03:00+08:00 

2.2.2、数组表示方式

在属性名书写位置的下方使用减号作为数据开始符号,每行书写一个数据,减号与数据间空格分隔

subject:
  - Java
  - PHP
  - Python
  - C++
  - C#
## 数组书写缩略格式
habby: [吃饭,睡觉,上班]

## 对象数组格式
users1: 
  - name: zhangsan
    age: 20
  - name: lisi
    age: 18

## 对象数组格式二
users2: 
  -
    name: zhangsan
    age: 20
  -
    name: lisi
    age: 18 

## 对象数组缩略格式
users3: [ { name:zhangsan , age:20 } , { name:lisi , age:18 } ]

数组获取
@Value("${subject[1]}")

2.2.3、yaml数据读取

1、使用@Value读取单个数据
属性名引用方式:${一级属性名.二级属性名……}

server:
  port: 9090

name: zhangsan

subject:
  - Java
  - PHP
  - Python
  - C++
  - C#
@RequestMapping("/")
@RestController
public class TestController {
    @Value("${name}")
    private String name;

    @Value("${server.port}")
    private String port;

    @Value("${subject[1]}")
    private String[] subject;

    @GetMapping("/getValue")
    public void getValue() {
        System.out.println("name = " + name);
        System.out.println("port = " + port);
        System.out.println("subject = " + Arrays.toString(subject));
    }
}

在配置文件中可以使用属性名引用方式引用属性

baseUrl: /opt/home
software:
  redis: ${baseUrl}/redis
  mysql: ${baseUrl}/mysql
@Value("${name}")
private String name;

@Value("${server.port}")
private String port;

@Value("${subject[1]}")
private String[] subject;

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

@Value("${software.redis}")
private String redis;

@Value("${software.mysql}")
private String mysql;

属性值中如果出现转移字符,需要使用双引号包裹

content: "你好\t我好\n大家好"

2、封装全部数据到Environment对象

@Autowired
private Environment environment;

@GetMapping("/getValue")
public void getValue() {
    ...
    System.out.println(environment.getProperty("name"));
    System.out.println(environment.getProperty("server.port"));
    System.out.println(environment.getProperty("subject[1]"));
}

3、ConfigurationProperties 通过自定义对象封装指定数据

user:
  userName: zhangsan
  age: 18
  habby:
    - 井空
    - 小泽
    - 波多
@Data
@Component  //必须要交给spring管理
@ConfigurationProperties(prefix = "user")
public class User {
    private String userName;
    private Integer age;
    private String[] habby;
}
@Autowired
private User user;

总结

  1. 使用@ConfigurationProperties注解绑定配置信息到封装类中
  2. 封装类需要定义为Spring管理的bean,否则无法进行属性注入

2.3、多环境开发

多数项目都会有开发环境、测试环境、生产环境,各个环境配置可能都会不一样,于是在构建时,会涉及到环境配置的切换。来回手工修改配置,效率低下,容易出错。可以配置多个含有不同环境配置的Profile,在构建时指定构建环境,达到多环境下快速灵活构建的目的,profile功能就是来进行动态配置切换的。在SpringBoot之前,采用的是maven多环境配置。

2.3.1、maven配置方式

<profiles>
    <profile>
        <!--开发环境,这个id就是名称-->
        <id>dev</id>
        <properties>
            <!--这个标签就是定义你要设定的properties中的属性-->
            <isFlag>true</isFlag>
        </properties>
    </profile>
    <profile>
        <!--生产环境-->
        <id>test</id>
        <properties>
            <isFlag>true</isFlag>
        </properties>
    </profile>
    <profile>
        <!--生产环境-->
        <id>pro</id>
        <properties>
            <isFlag>true</isFlag>
        </properties>
    </profile>
</profiles>

2.3.2、springboot配置方式

profile是用来完成不同环境下,配置动态切换功能的。

2.3.2.1、yml方式
# 启动指定环境
spring:
	profiles:
		active: pro
# 设置生产环境
---
spring:
	profiles: pro
server:
	port: 80
# 设置开发环境
---
spring:
	profiles: dev
server:
	port: 81
# 设置测试环境
---
spring:
	profiles: test
server:
	port: 82
2.3.2.2、properties方式

主启动配置文件application.properties

spring.profiles.active=dex

环境分类配置文件application-dex.properties

server.port=80

环境分类配置文件application-test.properties

server.port=81

环境分类配置文件application-pro.properties

server.port=82
2.3.2.3、多环境开发独立配置文件

方式一:

根据功能对配置文件中的信息进行拆分,并制作成独立的配置文件,命名规则如下

  • application-devDB.yml
  • application-devRedis.yml
  • application-devMVC.yml

使用include属性在激活指定环境的情况下,同时对多个环境进行加载使其生效,多个环境间使用逗号分隔

spring:
	profiles:
		active: dev
		include: devDB,devRedis,devMVC

当主环境dev与其他环境有相同属性时,主环境属性生效;其他环境中有相同属性时,最后加载的环境属性生效

方式二:

  • 从Spring2.4版开始使用group属性替代include属性,降低了配置书写量
  • 使用group属性定义多种主环境与子环境的包含关系
spring:
	profiles:
	active: dev
	group:
		"dev": devDB,devRedis,devMVC
		"pro": proDB,proRedis,proMVC
		"test": testDB,testRedis,testMVC

2.3.3、Maven与SpringBoot多环境兼容

1、Maven中设置多环境属性

<profiles>
    <profile>
        <id>dev_env</id>
        <properties>
            <profile.active>dev</profile.active>
        </properties>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <profile>
        <id>pro_env</id>
        <properties>
            <profile.active>pro</profile.active>
        </properties>
    </profile>
    <profile>
        <id>test_env</id>
        <properties>
            <profile.active>test</profile.active>
        </properties>
    </profile>
</profiles>

2、SpringBoot中引用Maven属性

spring:
  profiles:
    active: @profile.active@

3、执行Maven打包指令,并在生成的boot打包文件.jar文件中查看对应信息

总结

  • 当Maven与SpringBoot同时对多环境进行控制时,以Mavn为主,SpringBoot使用@…@占位符读取Maven对应的配置属性值
  • 基于SpringBoot读取Maven配置属性的前提下,如果在Idea下测试工程时pom.xml每次更新需要手动compile方可生效

2.3.4、总结

profile配置方式

  • 多profile文件方式
  • yml多文档方式

profile激活方式

  • 配置文件
  • 虚拟机参数
  • 命令行参数

profile配置方式

  • 多profile文件方式:提供多个配置文件,每个代表一种环境。
    application-dev.properties/yml 开发环境
    application-test.properties/yml 测试环境
    application-pro.properties/yml 生产环境

  • yml多文档方式
    在yml中使用 — 分隔不同配置

  • profile激活方式

    • 配置文件: 再配置文件中配置:spring.profiles.active=dev
    • 虚拟机参数:在VM options 指定:-Dspring.profiles.active=dev
    • 命令行参数:java –jar xxx.jar --spring.profiles.active=dev

2.4、内部配置加载顺序

Springboot程序启动时,会从以下4级加载配置文件:

  • 1级: file :config/application.yml 【最高】
  • 2级: file :application.yml
  • 3级:classpath:config/application.yml
  • 4级:classpath:application.yml 【最低】

作用

  • 1级与2级留做系统打包后设置通用属性,1级常用于运维经理进行线上整体项目部署方案调控
  • 3级与4级用于系统开发阶段设置通用属性,3级常用于项目经理进行整体项目属性调控

加载顺序为上文的排列顺序,高优先级配置的属性会生效。

配置文件分为4种

  • 项目类路径配置文件:服务于开发人员本机开发与测试
  • 项目类路径config目录中配置文件:服务于项目经理整体调控
  • 工程路径配置文件:服务于运维人员配置涉密线上环境
  • 工程路径config目录中配置文件:服务于运维经理整体调控

多层级配置文件间的属性采用叠加并覆盖的形式作用于程序

三、日志

3.1、日志基础操作

日志(log)作用

  • 编程期调试代码
  • 运营期记录信息
    • 记录日常运营重要信息(峰值流量、平均响应时长……)
    • 记录应用报错信息(错误堆栈)
    • 记录运维过程数据(扩容、宕机、报警……)

3.2、代码中使用日志工具记录日志

1、添加日志记录操作

@RestController
@RequestMapping("/books")
public class BookController {
    private static final Logger log = LoggerFactory.getLogger(BookController.class);

    @GetMapping
    public String getById() {
        System.out.println("springboot is running...");
        log.debug("debug ...");
        log.info("info ...");
        log.warn("warn ...");
        log.error("error ...");
        return "springboot is running...";
    }
}

日志级别

  • TRACE:运行堆栈信息,使用率低
  • DEBUG:程序员调试代码使用
  • INFO:记录运维过程数据
  • WARN:记录运维过程报警数据
  • ERROR:记录错误堆栈信息
  • FATAL:灾难信息,合并计入ERROR
    2、设置日志输出级别
# 开启 debug 模式,输出调试信息,常用于检查系统运行状况
debug: true
# 设置日志级别, root 表示根节点,即整体应用日志级别
logging:
  level:
    root: debug

3、设置日志组,控制指定包对应的日志输出级别,也可以直接控制指定包对应的日志输出级别

logging:
  # 设置日志组
  group:
    # 自定义组名,设置当前组中所包含的包
    ebank: com.java521.controller
  level:
    root: warn
    # 为对应组设置日志级别
    ebank: debug
    # 为对包设置日志级别
    com.java521.controller: debug

小结

  1. 日志用于记录开发调试与运维过程消息
  2. 日志的级别共6种,通常使用4种即可,分别是DEBUG,INFO,WARN,ERROR
  3. 可以通过日志组或代码包的形式进行日志显示级别的控制

优化日志对象创建代码

使用lombok提供的注解@Slf4j简化开发,减少日志对象的声明操作

@Slf4j
@RestController
@RequestMapping("/books")
public class BookController {
    @GetMapping
    public String getById() {
        System.out.println("springboot is running...");
        log.debug("debug ...");
        log.info("info ...");
        log.warn("warn ...");
        log.error("error ...");
        return "springboot is running...";
    }
}

3.3、日志输出格式控制

在这里插入图片描述
PID:进程ID,用于表明当前操作所处的进程,当多服务同时记录日志时,该值可用于协助程序员调试程序

所属类/接口名:当前显示信息为SpringBoot重写后的信息,名称过长时,简化包名书写为首字母,甚至直接删除

设置日志输出格式

logging:
  pattern:
    console: "%d - %m%n"
  • %d:日期
  • %m:消息
  • %n:换行
logging:
  pattern:
    console: "%d %clr(%p) --- [%16t] %clr(%-40.40c){cyan} : %m %n"

3.4、日志文件

logging:
  file:
    name: server.log

日志文件详细配置

logging:
  file:
    name: server.log
  logback:
    rollingpolicy:
      max-file-size: 3KB
      file-name-pattern: server.%d{yyyy-MM-dd}.%i.log

四、整合第三方技术

4.1、整合JUnit

@SpringBootTest
class ApplicationTests {
    @Autowired
    private User user;

    @Test
    public void contextLoads() {
        System.out.println(user);
    }
}
  • 名称:@SpringBootTest
  • 类型:测试类注解
  • 位置:测试类定义上方
  • 作用:设置JUnit加载的SpringBoot启动类
  • 范例:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
class ApplicationTests {
  • 相关属性
    classes:设置SpringBoot启动类

如果测试类在SpringBoot启动类的包或子包中,可以省略启动类的设置,也就是省略classes的设定

4.2、整合Redis

省略

4.3、整合Mybatis

省略

五、SpringBoot 自动配置

5.1、Condition

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

SpringBoot是如何知道要创建哪个Bean的?比如SpringBoot是如何知道要创RedisTemplate的?

新建SpringBoot项目,添加依赖。

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

启动类

@SpringBootApplication
public class SpringbootConditionApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);
       Object redisTemplate = context.getBean("redisTemplate");
        System.out.println("redisTemplate = " + redisTemplate);
    }
}

启动项目,报错
在这里插入图片描述
添加依赖

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

启动项目,成功
在这里插入图片描述
添加依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>

案例:需求
在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:

  1. 导入Jedis坐标后,加载该Bean,没导入,则不加载。
  2. 将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定。

添加依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.7.0</version>
</dependency>

User实体

public class User {
}

UserConfig

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

ClassCondition

public class ClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        try {
            Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
            return true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        }
    }
}

修改启动类

@SpringBootApplication
public class SpringbootConditionApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);
        //Object redisTemplate = context.getBean("redisTemplate");
        //System.out.println("redisTemplate = " + redisTemplate);

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

分别测试添加Jedis坐标和不添加Jedis坐标

添加Jedis坐标
在这里插入图片描述
没有添加Jedis坐标
在这里插入图片描述
改造:判断是否添加任意的类

添加:ConditionOnClass

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

UserConfig

@Configuration
public class UserConfig {
    @Bean
    //@Conditional(ClassCondition.class)
    @ConditionOnClass("redis.clients.jedis.Jedis")
    public User user(){
        return new User();
    }
}

分别测试添加和不添加Jedis坐标

public class ClassCondition implements Condition {
    /**
     * @param context  上下文对象。用于获取环境,IOC容器,ClassLoader对象
     * @param metadata 注解元对象。 可以用于获取注解定义的属性值
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //2.需求: 导入通过注解属性值value指定坐标后创建Bean
       /* try {
            Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
            return true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        }*/
        //2.需求: 导入通过注解属性值value指定坐标后创建Bean
        Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        System.out.println(map);
        String[] value = (String[]) map.get("value");
        boolean falg = true;
        try {
            for (String clasName : value) {
                Class<?> aClass = Class.forName(clasName);
            }
        } catch (ClassNotFoundException e) {
            falg = falg;
        }
        return falg;
    }
}

可用springboot提供 @ConditionalOnProperty 当存在配置才会创建bean

java=helloworld

UserConfig

@Configuration
public class UserConfig {
    @Bean
    //@Conditional(ClassCondition.class)
    //@ConditionOnClass("redis.clients.jedis.Jedis")
    public User user() {
        return new User();
    }

    @Bean
    @ConditionalOnProperty(name = "java", havingValue = "helloworld")
    public User user2() {
        return new User();
    }
}

SpringbootConditionApplication

SpringBootApplication
public class SpringbootConditionApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);
        //Object redisTemplate = context.getBean("redisTemplate");
        //System.out.println("redisTemplate = " + redisTemplate);

        Object user2 = context.getBean("user2");
        System.out.println("user2 = " + user2);
    }
}

Condition – 小结

  • 自定义条件:
    • 定义条件类:自定义类实现Condition接口,重写 matches 方法,在 matches 方法中进行逻辑判断,返回boolean值 。 matches 方法两个参数:
      • context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。
      • metadata:元数据对象,用于获取注解属性。
    • 判断条件: 在初始化Bean时,使用 @Conditional(条件类.class)注解
  • SpringBoot 提供的常用条件注解:
    • ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
    • ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
    • ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

5.2、切换内置web服务器

SpringBoot的web环境中默认使用tomcat作为内置服务器,其实SpringBoot提供了4中内置服务器供我们选择,我们可以很方便的进行切换。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!--排除tomcat依赖-->
    <exclusions>
        <exclusion>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <groupId>org.springframework.boot</groupId>
        </exclusion>
    </exclusions>
</dependency>

<!--引入jetty的依赖-->
<dependency>
    <artifactId>spring-boot-starter-jetty</artifactId>
    <groupId>org.springframework.boot</groupId>
</dependency>

在这里插入图片描述

5.3、@Enable*注解

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

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

创建springboot-enable 和 springboot-enable-other 不导入任何坐标

springboot-enable-other添加

public class User {
}

UserConfig

@Configuration
public class UserConfig {

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

springboot-enable 添加依赖

<dependency>
    <groupId>com.java521</groupId>
    <artifactId>spirngboot-bean-other</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

springboot-enable修改启动类

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

启动springboot-enable 报错 原因是因为springboot 不能直接获取其它工程中定义的bean

com.java521.springbootenable
com.java521.config
@ComponentScan 扫描的是当前类所在包和其子包
1.使用@ComponentScan扫描com.itheima.config包
2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器
3.可以对Import注解进行封装。

SpringbootEnableApplication

@SpringBootApplication
@ComponentScan("com.java521.config")
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);
    }
}

启动测试:

@SpringBootApplication
//@ComponentScan("com.java521.config")
@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);
    }
}

spirngboot-enable-other 添加自定义注解

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

springboot-enable 修改启动类

@SpringBootApplication
//@ComponentScan("com.java521.config")
//@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);
    }
}

5.4、@Import注解

@Enable*底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中。而@Import提供4中用法:

  1. 导入Bean
  2. 导入配置类
  3. 导入 ImportSelector 实现类。一般用于加载配置文件中的类
  4. 导入 ImportBeanDefinitionRegistrar 实现类

1、导入Bean

@SpringBootApplication
//@ComponentScan("com.java521.config")
//@Import(UserConfig.class)
//@EnableUser
@Import(User.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);

        //导入后不一定还叫user 可以通过bean获取
        User user = context.getBean(User.class);
        System.out.println("user = " + user);

        //获取bean的名称
        Map<String, User> map = context.getBeansOfType(User.class);
        System.out.println(map);
    }
}

在这里插入图片描述2、导入配置类
spirngboot-enable-other 添加

public class Role {
}

修改UserConfig

@Configuration
public class UserConfig {

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

修改springboot-enable启动类

@SpringBootApplication
//@ComponentScan("com.java521.config")
//@Import(UserConfig.class)
//@EnableUser
@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);

        //导入后不一定还叫user 可以通过bean获取
        User user = context.getBean(User.class);
        System.out.println("user = " + user);

        //获取bean的名称
//        Map<String, User> map = context.getBeansOfType(User.class);
//        System.out.println(map);
        Role role = context.getBean(Role.class);
        System.out.println("role = " + role);
    }
}

在这里插入图片描述

使用@Import导入 配置类上的注解可以不加

public class UserConfig {
    @Bean
    public User user(){
        return new User();
    }
    @Bean
    public Role role(){
        return new Role();
    }
}

3、导入 ImportSelector 实现类。一般用于加载配置文件中的类
spirngboot-enable-other 添加ImportSelector 的实现类

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.java521.domain.User", "com.java521.domain.Role"};
    }
}

启动类

@SpringBootApplication
//@ComponentScan("com.java521.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(UserConfig.class)
@Import(MyImportSelector.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);

        //导入后不一定还叫user 可以通过bean获取
        User user = context.getBean(User.class);
        System.out.println("user = " + user);

        //获取bean的名称
//        Map<String, User> map = context.getBeansOfType(User.class);
//        System.out.println(map);
        Role role = context.getBean(Role.class);
        System.out.println("role = " + role);
    }
}

4、导入 ImportBeanDefinitionRegistrar 实现类。

public class MyImportBeanDefinitionRegistrar  implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        registry.registerBeanDefinition("user",beanDefinition);
    }
}

修改启动类

@SpringBootApplication
//@ComponentScan("com.java521.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(UserConfig.class)
//@Import(MyImportSelector.class)
@Import( MyImportBeanDefinitionRegistrar.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);

        //导入后不一定还叫user 可以通过bean获取
        User user = context.getBean(User.class);
        System.out.println("user = " + user);

        //获取bean的名称
//        Map<String, User> map = context.getBeansOfType(User.class);
//        System.out.println(map);
        Role role = context.getBean(Role.class);
        System.out.println("role = " + role);
    }
}

在这里插入图片描述
user成功 role失败 因为配置类中没有role

使用名称导入

@SpringBootApplication
//@ComponentScan("com.java521.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(UserConfig.class)
//@Import(MyImportSelector.class)
@Import( MyImportBeanDefinitionRegistrar.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);

        //导入后不一定还叫user 可以通过bean获取
//        User user = context.getBean(User.class);
//        System.out.println("user = " + user);

        //获取bean的名称
//        Map<String, User> map = context.getBeansOfType(User.class);
//        System.out.println(map);
//        Role role = context.getBean(Role.class);
//        System.out.println("role = " + role);
    }
}

5.5、@EnableAutoConfiguration 注解

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

5.6、自定义starter

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

案例:实现步骤
1、创建 redis-spring-boot-autoconfigure 模块
2、创建 redis-spring-boot-starter 模块,依赖 redis-spring- boot-autoconfigure的模块

<dependency>
    <groupId>com.java521</groupId>
    <artifactId>redis-spring-boot-autoconfigure</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

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

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.7.0</version>
</dependency>

RedisProperties

@ConfigurationProperties(prefix = "reids")
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;
    }
}

RedisAutoConfiguration

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

    //提供jedis的bean
    @Bean
    public Jedis jedis(RedisProperties redisProperties) {
        return new Jedis(redisProperties.getHost(), redisProperties.getPort());
    }
}

resources下创建META-INF/spring.factories, 添加内容

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.java521.redis.config.RedisAutoConfiguration

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

springboot-enable添加依赖

<dependency>
    <groupId>com.java521</groupId>
    <artifactId>redis-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

SpringbootEnableApplication

@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);
        jedis.set("name","java");
        String name = jedis.get("name");
        System.out.println("name = " + name);
    }
}

5、启动测试
在这里插入图片描述

5.7、Java 监听机制

SpringBoot 的监听机制,其实是对Java提供的事件监听机制的封装。
Java中的事件监听机制定义了以下几个角色:

  • 事件:Event,继承 java.util.EventObject 类的对象
  • 事件源:Source ,任意对象Object
  • 监听器:Listener,实现 java.util.EventListener 接口 的对象

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

添加依赖

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

5.7.1、ApplicationContextInitializer

@Component
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("ApplicationContextInitializer....initialize");
    }
}

5.7.2、SpringApplicationRunListener

/**
 * 当项目启动后执行run方法。
 */
@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner...run");
        System.out.println(Arrays.asList(args.getSourceArgs()));
    }
}

5.7.3、CommandLineRunner

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner...run");
        System.out.println(Arrays.asList(args));
    }
}

5.7.4、ApplicationRunner

public class MySpringApplicationRunListener implements SpringApplicationRunListener {

    public MySpringApplicationRunListener(SpringApplication application, String[] args) {
    }

    @Override
    public void starting() {
        System.out.println("starting...项目启动中");
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        System.out.println("environmentPrepared...环境对象开始准备");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("contextPrepared...上下文对象开始准备");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("contextLoaded...上下文对象开始加载");
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("started...上下文对象加载完成");
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("running...项目启动完成,开始运行");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("failed...项目启动失败");
    }
}

5.8、SpringBoot 启动流程分析

请添加图片描述

5.9、SpringBoot 监控

5.9.1、SpringBoot 监控概述

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

路径描述
/beans描述应用程序上下文里全部的Bean,以及它们的关系
/env获取全部环境属性
/env/{name}根据名称获取特定的环境属性值
/health报告应用程序的健康指标,这些值由HealthIndicator的实现类提供
/info获取应用程序的定制信息,这些信息由info打头的属性提供
/mappings描述全部的URI路径,以及它们和控制器(包含Actuator端点)的映射关系
/metrics报告各种应用程序度量信息,比如内存用量和HTTP请求计数
/metrics/{name}报告指定名称的应用程序度量值
/trace提供基本的HTTP请求跟踪信息(时间戳、HTTP头等)

5.9.2、SpringBoot 监控使用

1、导入依赖坐标

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


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

2、访问http://localhost:8080/acruator,返回的是JSON数据,我这里安装了浏览器JSON插件。
在这里插入图片描述
3、Info相关
修改配置文件

info.name=zhangsan
info.age=18

在这里插入图片描述
4、health相关
在这里插入图片描述
5、开启健康检查的完整信息

info.name=zhangsan
info.age=18
# 开启健康检查的完整信息
management.endpoint.health.show-details=always

在这里插入图片描述
6、检查第三方组件 比如redis,默认连接本地redis

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

在这里插入图片描述
关闭redis,重启项目
在这里插入图片描述
7、将所有的监控endpoints暴露出来,修改配置文件。

info.name=zhangsan
info.age=18
# 开启健康检查的完整信息
management.endpoint.health.show-details=always
# 将所有的监控endpoints暴露出来
management.endpoints.web.exposure.include=*

访问:http://localhost:8080/actuator
在这里插入图片描述
8、查看所有的url路径:http://localhost:8080/actuator/mappings

@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/findAll")
    public String findAll(){
        return "success";
    }
}

在这里插入图片描述

5.9.3、Spring Boot Admin

  • Spring Boot Admin是一个开源社区项目,用于管理和监控SpringBoot应用程序。
  • Spring Boot Admin 有两个角色,客户端(Client)和服务端(Server)。
  • 应用程序作为Spring Boot Admin Client向为Spring Boot Admin Server注册
  • pring Boot Admin Server 的UI界面将Spring Boot Admin Client的Actuator Endpoint上的
5.9.3.1、admin-server:

1、创建 admin-server 模块
2、导入依赖坐标 admin-starter-server

<?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.5.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.java521</groupId>
    <artifactId>springboot-admin</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-admin</name>
    <description>springboot-admin</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-boot-admin.version>2.4.3</spring-boot-admin.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-dependencies</artifactId>
                <version>${spring-boot-admin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

</project>

3、在引导类上启用监控功能@EnableAdminServer

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

4、编写配置文件

server:
  port: 8080
5.9.3.2、admin-client:

1、创建 admin-client 模块
2、导入依赖坐标 admin-starter-client

<?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.5.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.java521</groupId>
    <artifactId>springboot-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-client</name>
    <description>springboot-client</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-boot-admin.version>2.4.3</spring-boot-admin.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-dependencies</artifactId>
                <version>${spring-boot-admin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

</project>

3、配置相关信息:server地址等

server:
  port: 8081
# admin server 的地址
spring:
  boot:
    admin:
      client:
        url: http://localhost:8080
# 开放端点, 用于SpringBoot Admin的监控
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: '*'

4、启动server和client服务,访问server http://localhost:8080/
在这里插入图片描述
5、写一个Controller模拟一个普通的接口

@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/findAll")
    public String findAll(){
        return "success";
    }
}

6、测试,访问:http://localhost:8081/user/findAll,通过浏览器访问这个接口就会打印日志在这里插入图片描述
7、环境配置信息
在这里插入图片描述

5.10、SpringBoot 项目部署

  • jar包(官方推荐)
  • war包
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值