Java之Spring Boot入门到精通【IDEA版】SpringBoot原理分析,SpringBoot监控(一篇文章精通系列)【下】

x33g5p2x  于2021-11-09 转载在 Java  
字(48.9k)|赞(0)|评价(0)|浏览(338)
目录
Java之Spring Boot入门到精通【IDEA版】(一篇文章精通系列)【上】
Java之Spring Boot入门到精通【IDEA版】SpringBoot整合其他框架【Junit,Redis,MyBatis】(一篇文章精通系列)【中】
Java之Spring Boot入门到精通【IDEA版】SpringBoot原理分析,SpringBoot监控(一篇文章精通系列)【下】

一、SpringBoot自动配置

1、Condition(自定义条件)

Condition是在Spring 4.0增加的条件判断功能,通过这个可以功能可以实现选择性的创建Bear操作。
SpringBoot是如何知道要创建哪个Bean的?比如SpringBoot是如何知道要创建RedisTemplate的?

(1)搭建工程

(2)获取Bean,redisTemplate

package cn.itbluebox.springbootcondition;
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) {
        //启动SpringBoot的应用,返回Spring的IOC容器
        ConfigurableApplicationContext context
                = SpringApplication.run(SpringbootConditionApplication.class, args);
        //1、获取Bean,redisTemplate
        Object bean = context.getBean("redisTemplate");
        System.out.println(bean);
    }
}
  • 运行测试

运行报错因为,没有bean是叫redisTemplate

(3)引入redis的依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  • 重新运行测试

(4)在Spring的IOC容器中有一个User的Bean,
1)创建User相关内容

  • 创建UserConfig配置类

package cn.itbluebox.springbootcondition.config;
import cn.itbluebox.springbootcondition.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();
    }
}
  • 获取刚刚创建的User,修改SpringbootConditionApplication

package cn.itbluebox.springbootcondition;

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) {
        //启动SpringBoot的应用,返回Spring的IOC容器
        ConfigurableApplicationContext context
                = SpringApplication.run(SpringbootConditionApplication.class, args);
       /* 1、获取Bean,redisTemplate Object bean = context.getBean("redisTemplate"); System.out.println(bean); */
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
  • 运行测试

2)现要求:导入Jedis坐标后,加载该Bean,没导入,则不加载
  • 创建ClassCondition

package cn.itbluebox.springbootcondition.condtion;
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 context, AnnotatedTypeMetadata metadata) {

        return false;
    }
}
  • 修改UserConfig

现在这ClassCondition返回的是false所以不会创建user对应的Bean,只有返回true才会创建user对应的bean

package cn.itbluebox.springbootcondition.config;

import cn.itbluebox.springbootcondition.condtion.ClassCondition;
import cn.itbluebox.springbootcondition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {
    @Bean
    @Conditional(ClassCondition.class)//现在这ClassCondition返回的是false所以不会创建user对应的Bean
    public User user(){
        return new User();
    }
}
  • 运行测试

  • 运行报错,没有找到user对应的Bean

  • 修改ClassCondition将返回值修改为true

package cn.itbluebox.springbootcondition.condtion;
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 context, AnnotatedTypeMetadata metadata) {
        return true;
    }
}
  • 运行测试

user对应的Bean创建成功

  • 引入Jedis坐标

<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
  • 完成需求继续修改ClassCondition

package cn.itbluebox.springbootcondition.condtion;

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 context, AnnotatedTypeMetadata metadata) {
        //1、需求:导入Jedis坐标后,加载该Bean
        //2、思路:判断redis.clients.jedis.Jedis.class 文件是否存在
        boolean flag = true;
        try {
            //如果forName可以加载到对应Jedis字节码那么说明引入了Jedis的依赖
            Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
            flag = false;
            e.printStackTrace();
        }
        return flag;
    }
}
  • 运行测试

  • 可以获取到因为,引入了Jedis依赖

  • 删除Jedis的依赖

  • 再次运行

  • 运行报错,并且没有创建user对应的bean

2、Condition(条件)动态实现

  • 将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定。
(1)创建ConditionOnClass (自定义注解)

package cn.itbluebox.springbootcondition.condtion;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;

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

package cn.itbluebox.springbootcondition.config;
import cn.itbluebox.springbootcondition.condtion.ClassCondition;
import cn.itbluebox.springbootcondition.condtion.ConditionOnClass;
import cn.itbluebox.springbootcondition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {
    @Bean
   // @Conditional(ClassCondition.class)//现在这ClassCondition返回的是false所以不会创建user对应的Bean
    @ConditionOnClass("redis.clients.jedis.Jedis")
    public User user(){
        return new User();
    }
}
  • 运行测试

(3)使用导入的指定坐标
  • 修改ClassCondition

package cn.itbluebox.springbootcondition.condtion;
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 {
    /* context:上下文对象。用于获取一些环境,IOC容器,ClassLoader对象 metadata:注解元对象。可以用于获取注解定义的属性值。 */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //需求:导入通过注解属性值value指定的坐标
        //获取注解属性值 value
        Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        //System.out.println(map);
        String[] value = (String[])map.get("value");
        boolean flag = true;
        try {
            for(String className : value){
                //如果forName可以加载到对应Jedis字节码那么说明引入了Jedis的依赖
                Class<?> cls = Class.forName(className);
            }
        } catch (ClassNotFoundException e) {
            flag = false;
            e.printStackTrace();
        }
        return flag;
    }
}
  • 运行测试

(4)判断其他的坐标
  • 修改pom.xml

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.4</version>
        </dependency>
  • 修改UserConfig

  • 使用User对象必须引入fastjson的坐标
package cn.itbluebox.springbootcondition.config;

import cn.itbluebox.springbootcondition.condtion.ConditionOnClass;
import cn.itbluebox.springbootcondition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {
    @Bean
   // @Conditional(ClassCondition.class)//现在这ClassCondition返回的是false所以不会创建user对应的Bean
    @ConditionOnClass("com.alibaba.fastjson.JSON")
    public User user(){
        return new User();
    }
}
  • 运行测试

  • 查询成功

  • 删除依赖

(5)使用自带的ConditionalOnProperty判断
  • 修改UserConfig

@Bean
    @ConditionalOnProperty(name = "it",havingValue = "bluebox")
    public User user2(){
        return new User();
    }
  • 修改SpringbootConditionApplication

package cn.itbluebox.springbootcondition;

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) {
        //启动SpringBoot的应用,返回Spring的IOC容器
        ConfigurableApplicationContext context
                = SpringApplication.run(SpringbootConditionApplication.class, args);
       /* 1、获取Bean,redisTemplate Object bean = context.getBean("redisTemplate"); System.out.println(bean); */
        Object user = context.getBean("user2");
        System.out.println(user);
    }
}
  • 运行测试

获取不到,因为配置文件当中没有对应键值对

  • 完善application.properties

it=bluebox
  • 运行测试

SpringBoot提供的常用条件注解:

  • ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
  • ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
  • ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

3、切换内置web服务器

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

(1)修改pom.xml文件引入web依赖
  • 之前我们在启动项目的时候项目直接启动并运行完就结束了,没有Tomcat的日志信息输出

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
  • 运行测试

  • 启动并一直运行并输出对应Tomcat的日志信息

  • 分析一下spring-boot-starter-web的依赖情况

我们可以找到对应的Tomcat

  • 排除Tomcat的依赖

自动的排除了对应的依赖

(2)切换内置服务器

在上面我们在web当中排除了对应的Tomcat的依赖

1)切换到jetty
  • 修改pom.xml

<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>
  • 重新运行

  • 切换成功

4、@Enable* 注解

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

(1)演示不能获取第三方jar当中 Bean
1)创建模块
  • 创建模块一

  • 修改SpringbootEnableApplication

package cn.itbluebox.springbootenable;
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);
        //获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
  • 创建模块二

  • 修改springboot-enable-other当中的pom.xml删除一些现在用不上的依赖

  • 删除springboot-enable-other现阶段用不上的类

  • 编写配置类

package cn.itbluebox.config;
import cn.itbluebox.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();
    }
}
(2)获取第三方jar
1)第一种实现使用第三方的jar(使用@ComponentScan扫描cn.itbluebox.config)

springboot-enable当的pom.xml添加springboot-enable-other的对应的User的依赖

<dependency>
            <groupId>cn.itbluebox</groupId>
            <artifactId>springboot-enable-other</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
  • 运行测试springboot-enable当中的SpringbootEnableApplication

无法获取到user

所以光是引入其他工程的依赖是无法获取到其他工程的Bean
SpringbootEnableApplication上使用@ComponentScan("cn.itbluebox.config")需要扫描对应配置类所在的包

  • 修改springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config */

@SpringBootApplication
@ComponentScan("cn.itbluebox.config")
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}

运行测试

运行成功

2)第二种实现使用第三方的jar(使用@Import注解,加载类)
  • 修改SpringbootEnableApplication

package cn.itbluebox.springbootenable;
import cn.itbluebox.config.UserConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 */

@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
@Import(UserConfig.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
  • 运行测试

3)第三种实现使用第三方的jar(可以对Import注解进行封装)

在第三的springboot-enable-other当中提供对应的功能

  • 创建EnableUser

package cn.itbluebox.config;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}
  • 修改springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;

import cn.itbluebox.config.EnableUser;
import cn.itbluebox.config.UserConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 //3、可以对Import注解进行封装 */

@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
//@Import(UserConfig.class)
@EnableUser
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
  • 运行测试

5、@lmport注解

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

(1)导入Bean
  • 修改SpringbootEnableApplication

package cn.itbluebox.springbootenable;

import cn.itbluebox.config.EnableUser;
import cn.itbluebox.config.UserConfig;
import cn.itbluebox.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 //3、可以对Import注解进行封装 */

/* Import的4种用法: 1、导入Bean */

@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
//@Import(UserConfig.class)
//@EnableUser
@Import(User.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
        Object user = context.getBean("user");
        System.out.println(user);
    }
}
  • 运行测试

无法获取到

虽然通过@Import(User.class)引入创建了User的对象但是并不一定是getBean的时候叫user,通过User字节码获取

  • 修改springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;
import cn.itbluebox.config.EnableUser;
import cn.itbluebox.config.UserConfig;
import cn.itbluebox.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 //3、可以对Import注解进行封装 */
/* Import的4种用法: 1、导入Bean */
@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
//@Import(UserConfig.class)
//@EnableUser
@Import(User.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
       /* Object user = context.getBean("user"); System.out.println(user);*/
        User user = context.getBean(User.class);
        System.out.println(user);
    }
}

  • 获取一些其他属性

package cn.itbluebox.springbootenable;
import cn.itbluebox.config.EnableUser;
import cn.itbluebox.config.UserConfig;
import cn.itbluebox.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import java.util.Map;

/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 //3、可以对Import注解进行封装 */
/* Import的4种用法: 1、导入Bean */
@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
//@Import(UserConfig.class)
//@EnableUser
@Import(User.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
       /* Object user = context.getBean("user"); System.out.println(user);*/
        User user = context.getBean(User.class);
        System.out.println(user);
        Map<String, User> map = context.getBeansOfType(User.class);
        System.out.println(map);
    }
}
  • 运行测试

(2)导入配置类
  • 修改springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;
import cn.itbluebox.config.EnableUser;
import cn.itbluebox.config.UserConfig;
import cn.itbluebox.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import java.util.Map;

/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 //3、可以对Import注解进行封装 */
/* Import的4种用法: 1、导入Bean 2、导入配置类 */

@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(User.class)
@Import(UserConfig.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
       /* Object user = context.getBean("user"); System.out.println(user);*/
        User user = context.getBean(User.class);
        System.out.println(user);
        Map<String, User> map = context.getBeansOfType(User.class);
        System.out.println(map);
    }
}
  • 在springboot-enable-other当中创建Role对象

  • 修改springboot-enable-other当中的UserConfig

  • Role也会创建到Spring的IOC容器当中
package cn.itbluebox.config;
import cn.itbluebox.domain.Role;
import cn.itbluebox.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();
    }
    @Bean
    public Role role(){
        return new Role();
    }
}
  • 完善springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;
import cn.itbluebox.config.EnableUser;
import cn.itbluebox.config.UserConfig;
import cn.itbluebox.domain.Role;
import cn.itbluebox.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.util.Map;
/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 //3、可以对Import注解进行封装 */
/* Import的4种用法: 1、导入Bean 2、导入配置类 */
@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(User.class)
@Import(UserConfig.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
       /* Object user = context.getBean("user"); System.out.println(user);*/
        User user = context.getBean(User.class);
        System.out.println(user);

        Role role = context.getBean(Role.class);
        System.out.println(role);
        /* Map<String, User> map = context.getBeansOfType(User.class); System.out.println(map); */
    }
}
  • 运行测试

  • springboot-enable当中的SpringbootEnableApplication上使用@Import注解的时候在springboot-enable-other当中的UserConfig上可以不使用 @Configuration注解

  • 运行测试

(3)导入ImportSelector实现类。一般用于加载配置文件中的类
  • 源代码
public interface ImportSelector {
	String[] selectImports(AnnotationMetadata importingClassMetadata);
	@Nullable
	default Predicate<String> getExclusionFilter() {
		return null;
	}
}
  • 在springboot-enable-other当中创建MyImportSelector,去实现ImportSelector接口

package cn.itbluebox.config;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"cn.itbluebox.domain.User","cn.itbluebox.domain.Role"};
    }
}
  • 修改springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;

import cn.itbluebox.config.EnableUser;
import cn.itbluebox.config.MyImportSelector;
import cn.itbluebox.config.UserConfig;
import cn.itbluebox.domain.Role;
import cn.itbluebox.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector;

import java.util.Map;

/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 //3、可以对Import注解进行封装 */

/* Import的4种用法: 1、导入Bean 2、导入配置类 3、导入ImportSelector的实现类。 */

@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(User.class)
//@Import(UserConfig.class)
@Import(MyImportSelector.class)
public class SpringbootEnableApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
        //获取Bean
       /* Object user = context.getBean("user"); System.out.println(user);*/
        User user = context.getBean(User.class);
        System.out.println(user);

        Role role = context.getBean(Role.class);
        System.out.println(role);
        /* Map<String, User> map = context.getBeansOfType(User.class); System.out.println(map); */
    }
}
  • 运行测试

(4)导入ImportBeanDefinitionRegistrar实现类。
  • 在springboot-enable-other当中创建

package cn.itbluebox.config;
import cn.itbluebox.domain.User;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry ) {
        AbstractBeanDefinition beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        registry.registerBeanDefinition("user",beanDefinitionBuilder);

    }

}
  • 完善springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;

import cn.itbluebox.config.EnableUser;
import cn.itbluebox.config.MyImportBeanDefinitionRegistrar;
import cn.itbluebox.config.MyImportSelector;
import cn.itbluebox.config.UserConfig;
import cn.itbluebox.domain.Role;
import cn.itbluebox.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector;

import java.util.Map;

/* @ComponentScan 扫描范围:是当前引导类所在包,及其子包 cn.itbluebox.springbootenable User在cn.itbluebox.config当中 上述两个包直接没有任何包含关系 //1、使用@ComponentScan扫描cn.itbluebox.config //2、使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器 //3、可以对Import注解进行封装 //4、导入ImportBeanDefinitionRegistrar的实现类 */

/* Import的4种用法: 1、导入Bean 2、导入配置类 3、导入ImportSelector的实现类。 */

@SpringBootApplication
//@ComponentScan("cn.itbluebox.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(User.class)
//@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);
        //获取Bean
       /* Object user = context.getBean("user"); System.out.println(user);*/
        User user = context.getBean(User.class);
        System.out.println(user);

        Role role = context.getBean(Role.class);
        System.out.println(role);
        /* Map<String, User> map = context.getBeansOfType(User.class); System.out.println(map); */
    }
}
  • 运行测试

user获取成功,但是Role没有获取成功(因为在MyImportBeanDefinitionRegistrar没有导入Role的)

6、@EnableAutoConfiguration注解

  • 源代码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}
  • @EnableAutoConfiauration注解内部使用@Import (AutoConficurationImportSelector.class)来加载配置类。
  • 配置文件位置: META-INF/spring.factories,该配置文件中定义了大量的配置类,当SpringBoot应用启动时,会自动加载这些配置类,初始化Bean
  • 并不是所有的Bean都会被初始化,在配置类中使用Condition来加载满足条件的Bean
    (注意spring.factories当中的配置类在Spring启动的时候并不会全部创建在每一个类上都有ConditionalOnClass判断是否需要加载当前对象)

7、自定义starter步骤分析

案例:
需求:自定义redis-starter。要求当导入redis坐标时,SpringBoot自动创建Jedis的Bean。
实现上述需求,我们可以参考MyBatis

(1)创建redis-spring-boot-autoconfigure模块

(2)创建redis-spring-boot-starter模块,依赖redis-spring-boot-autoconfigure的模块

(3)修改创建好的两个模块对其进行瘦身
1)修改redis-spring-boot-starter当中的内容对其进行瘦身
  • 删除一些文件

  • 修改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.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.itbluebox</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>
        <!--引入configure-->
        <dependency>
            <groupId>cn.itbluebox</groupId>
            <artifactId>redis-spring-boot-autoconfigure</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
  • 删除启动类和测试类

2)修改redis-spring-boot-autoconfigure对其进行瘦身
  • 删除一些文件

  • 修改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.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.itbluebox</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>
    </dependencies>

</project>
  • 删除启动类和测试类

(3)在redis-spring-boot-autoconfigure模块中初始化Jedis的Bean。并定义META-INF/spring.factories文件
1)创建RedisAutoConfiguration

package cn.itbluebox.redis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
@Configuration
public class RedisAutoConfiguration {
    /* 提供Jedis的Bean */
    @Bean
    public Jedis jedis(){
        return new Jedis();
    }
}
2)创建RedisProperties

package cn.itbluebox.redis.config;

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;
    }
}
3)完善RedisAutoConfiguration

package cn.itbluebox.redis.config;

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

@Configuration
@EnableConfigurationProperties(RedisProperties.class)//设置完之后RedisProperties会被Spring所识别
public class RedisAutoConfiguration {

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

}
4)创建spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  cn.itbluebox.redis.config.RedisAutoConfiguration
(4)在测试模块中引入自定义的redis-starter依赖,测试获取Jedis的Bean,操作redis。
  • 修改springboot-enable当中pom.xml

<dependency>
            <groupId>cn.itbluebox</groupId>
            <artifactId>redis-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
  • 继续完善springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;

import cn.itbluebox.config.MyImportBeanDefinitionRegistrar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
import redis.clients.jedis.Jedis;

@SpringBootApplication
@Import({MyImportBeanDefinitionRegistrar.class})
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);
    }
}
  • 运行测试

(5)操作上述获取到的Jedis
  • 启动本机的redis

在SpringbootEnableApplication操作redis存入数据,并获取数据

package cn.itbluebox.springbootenable;
import cn.itbluebox.config.MyImportBeanDefinitionRegistrar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
import redis.clients.jedis.Jedis;
@SpringBootApplication
@Import({MyImportBeanDefinitionRegistrar.class})
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.set("name","itbluebox");
        String name = jedis.get("name");
        System.out.println(name);
    }
}
  • 运行测试

(6)编写配置文件设置redis的属性
1)设置端口号

RedisProperties会绑定到对应的配置文件读取配置文件当中的信息

  • 在springboot-enable当中的application.properties设置端口号

redis.port=6666

更改端口号后一定报错,但是证明配置修改成功

  • 运行测试

2)在RedisAutoConfiguration上设置一些条件
  • 修改redis-spring-boot-autoconfigure当中的RedisAutoConfiguration

package cn.itbluebox.redis.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;

@Configuration
@EnableConfigurationProperties(RedisProperties.class)//设置完之后RedisProperties会被Spring所识别
@ConditionalOnClass(Jedis.class)//设置Jedis存在的时候才去加载
public class RedisAutoConfiguration {

    /* 提供Jedis的Bean */
    @Bean
    @ConditionalOnMissingBean(name = "jedis")//如果用户定义了自己的Jedis就使用用户自定义的Jedis,没有没有定义使用当前的
    public Jedis jedis(RedisProperties redisProperties){
        System.out.println("RedisAutoConfiguration.....");
        return new Jedis(redisProperties.getHost(),redisProperties.getPort());
    }

}
  • 运行测试
    设置正确的端口号

运行

  • 修改springboot-enable当中的SpringbootEnableApplication

package cn.itbluebox.springbootenable;
import cn.itbluebox.config.MyImportBeanDefinitionRegistrar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import redis.clients.jedis.Jedis;

@SpringBootApplication
@Import({MyImportBeanDefinitionRegistrar.class})
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.set("name","itbluebox2");
        String name = jedis.get("name");
        System.out.println(name);
    }

    @Bean
    public Jedis jedis(){
        return new Jedis("localhost",6379);
    }
}
  • 运行测试

没有输出RedisAutoConfiguration.....证明RedisAutoConfiguration@ConditionalOnMissingBean(name = "jedis")生效的

二、SpringBoot监听机制

1、Java的监听机制

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

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

2、SpringBoot 监听机制

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

3、代码演示

(1)创建模块

  • 创建包结构

(2)创建对应的监听对象
  • 创建MyApplicationContextInitializer

package cn.itbluebox.springbootlistener.listener;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

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

package cn.itbluebox.springbootlistener.listener;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;

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...项目启动失败");
    }
}
  • 创建MyCommandLineRunner

package cn.itbluebox.springbootlistener.listener;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Arrays;

public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner...run");
    }
}
  • 创建MyApplicationRunner

package cn.itbluebox.springbootlistener.listener;

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

import java.util.Arrays;

/** * 当项目启动后执行run方法。 */

public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner...run");
    }
}
  • 完善上述四个并将其注册到Spring容器当中
    MyApplicationContextInitializer

package cn.itbluebox.springbootlistener.listener;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

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

MyApplicationRunner

package cn.itbluebox.springbootlistener.listener;

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

import java.util.Arrays;

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

MyCommandLineRunner

package cn.itbluebox.springbootlistener.listener;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner...run");
    }
}
(3)运行测试

我们观察到上述只执行了两个监听对象

MyApplicationRunner
MyCommandLineRunner

  • 设置输出一下对应MyApplicationRunner和MyCommandLineRunner的args
    MyApplicationRunner

package cn.itbluebox.springbootlistener.listener;

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

import java.util.Arrays;

/** * 当项目启动后执行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()));
    }
}

**MyCommandLineRunner **

package cn.itbluebox.springbootlistener.listener;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Arrays;

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

运行测试

  • 其中args对应的是参数运行时候传递的一些参数
  • 设置运行时传递一些参数

  • 启动运行测试

(4)运行测试而MySpringApplicationRunListener和MyApplicationContextInitializer的执行需要设置配置文件
1)MyApplicationContextInitializer
  • 创建spring.factories

org.springframework.context.ApplicationContextInitializer=cn.itbluebox.springbootlistener.listener.MyApplicationContextInitializer
  • 运行测试

运行成功

2)MySpringApplicationRunListener

org.springframework.boot.SpringApplicationRunListener = cn.itbluebox.springbootlistener.listener.MySpringApplicationRunListener
  • 运行测试

运行成功

三、SpringBoot启动流程分析

1、SpringBoot启动流程图

四、SpringBoot监控

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

1、创建工程

1)创建模块

2)通过上述方式已经引入了依赖

<?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.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.itbluebox</groupId>
    <artifactId>springboot-actuator</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-actuator</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-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

</project>

而其中下面这段是SpringBoot的监控的依赖

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

2、访问http://localhost:8080/acruator

启动项目

访问http://localhost:8080/actuator

http://localhost:8080/actuator/health

3、设置开启健康

修改application.properties

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

再次访问:http://localhost:8080/actuator/health/

4、设置引入redis

引入redis的依赖

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

重新运行项目

访问:http://localhost:8080/actuator/health/
因为没有我的电脑没有开启redis所以,redis报错了

启动本机redis

再次访问:http://localhost:8080/actuator/health/

5、监控的其他使用

1)actuator开启所有endpoint

修改application.properties

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
    },
    "configprops-prefix": {
      "href": "http://localhost:8080/actuator/configprops/{prefix}",
      "templated": true
    },
    "env": {
      "href": "http://localhost:8080/actuator/env",
      "templated": false
    },
    "env-toMatch": {
      "href": "http://localhost:8080/actuator/env/{toMatch}",
      "templated": true
    },
    "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
    }
  }
}
2)我们来使用一些比较常用的
01)http://localhost:8080/actuator/beans

东西太多了只粘贴一部分信息

02)http://localhost:8080/actuator/mappings

创建UserController

package cn.itbluebox.springbootactuator;

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

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("findAll")
    public String findAll(){
        return "SUCCESS";
    }

}

重新运行测试

访问:http://localhost:8080/actuator/mappings

6、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 AdminClientActuatorEndpoint上的一些监控信息。
(1)admin-server
1)创建admin-server模块

2)导入依赖坐标admin-starter-server

通过上述的创建方式已经自动引入了对应的依赖

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

开启服务
在springboot-admin-server当中的SpringbootAdminServerApplication上设置@EnableAdminServer

package cn.itbluebox.springbootadminserver;
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);
    }
}
4)修改端口号

server.port=9000
(2)admin-client
1)创建admin-client模块

2)导入依赖坐标admin-starter-client

通过上述的方式已经自动引入了对应的依赖

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

#指定admin.server的地址
spring.boot.admin.client.url=http://localhost:9000

# 开启健康检查
management.endpoint.health.show-details=always
# 开启所有的配置
management.endpoints.web.exposure.include=*
4)启动server和client服务,访问server
1>启动server

启动成功

2> 启动client

3>访问http://localhost:9000/applications

4>性能

创建UserController

package cn.itbluebox.springbootadminclient;

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

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("findAll")
    public String findAll(){
        return "SUCCESS";
    }

}

重新运行springboot-admin-client

运行成功

访问http://localhost:8080/user/findAll

再次访问:http://localhost:9000/instances/4664fd8429f6/metrics

再次访问http://localhost:8080/user/findAll

被访问次数变成2

5>环境电脑的环境和配置信息

6>类信息

7>配置属性

8>计划任务

9>JVM

线程

10>映射

5)IDEA的

目录
Java之Spring Boot入门到精通【IDEA版】(一篇文章精通系列)【上】
Java之Spring Boot入门到精通【IDEA版】SpringBoot整合其他框架【Junit,Redis,MyBatis】(一篇文章精通系列)【中】
Java之Spring Boot入门到精通【IDEA版】SpringBoot原理分析,SpringBoot监控(一篇文章精通系列)【下】

相关文章

微信公众号

最新文章

更多

目录