• SpringBoot快速入门--高级版


    基础版转到:SpringBoot快速入门–基础版(包含整合常用框架、跨域)

    SpringBoot 自动配置

    Condition

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

    需求

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

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

    创建Spring Boot项目,勾选Spring Web

    ①创建User类

    package com.aiw.springbootcondition.pojo;
    
    public class User {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ②创建配置类

    package com.aiw.springbootcondition.config;
    
    import com.aiw.springbootcondition.condition.ClassCondition;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    
    import com.aiw.springbootcondition.pojo.User;
    
    @Configuration // 标识为配置类
    public class UserConfig {
    
        @Bean
        @Conditional(ClassCondition.class)
        public User user() {
            return new User();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ③实现Condition接口类

    package com.aiw.springbootcondition.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 context, AnnotatedTypeMetadata metadata) {
            // 需求:导入Jedis坐标后创建Bean
            // 思路:判断redis.clients.jedis.Jedis文件是否存在
            boolean flag = true;
            try {
                Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                flag = false;
            }
            return flag;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    ④主程序

    package com.aiw.springbootcondition;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    
    import com.aiw.springbootcondition.pojo.User;
    
    @SpringBootApplication
    public class SpringbootConditionApplication {
    
    	public static void main(String[] args) {
    		// 启动Spring Boot的应用,返回Spring的IOC容器
    		ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);
    
    		Object user = context.getBean("user", User.class);
    		System.out.println(user);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    若在pom.xml文件中导入了如下jedis坐标,则能获取到User Bean,否则获取不到

    <dependency>
    	<groupId>redis.clientsgroupId>
    	<artifactId>jedisartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    目前到此,只实现了一半需求,继续完善如下,新建注解

    package com.aiw.springbootcondition.condition;
    
    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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    修改ClassCondition.java

    package com.aiw.springbootcondition.condition;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    import org.springframework.util.MultiValueMap;
    
    public class ClassCondition implements Condition {
        /**
         * @param context  上下文对象。用于获取环境,IOC容器,CLassLoader对象
         * @param metadata 注解元对象。用于获取注解定义的属性值
         * @return
         */
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    //        // 需求:导入Jedis坐标后创建Bean
    //        // 思路:判断redis.clients.jedis.Jedis文件是否存在
    //        boolean flag = true;
    //        try {
    //            Class cls = Class.forName("redis.clients.jedis.Jedis");
    //        } catch (ClassNotFoundException e) {
    //            e.printStackTrace();
    //            flag = false;
    //        }
    //        return flag;
    
            // 需求:导入通过注解属性值value指定坐标后创建Bean
            // 获取注解属性值 value
            MultiValueMap<String, Object> map = metadata.getAllAnnotationAttributes(ConditionOnClass.class.getName());
            String[] value = (String[]) map.get("value").get(0);
            boolean flag = true;
            try {
                for (String className : value) {
                    Class<?> cls = Class.forName(className);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                flag = false;
            }
            return flag;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    再修改UserConfig.java

    package com.aiw.springbootcondition.config;
    
    import com.aiw.springbootcondition.condition.ConditionOnClass;
    import com.aiw.springbootcondition.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration // 标识为配置类
    public class UserConfig {
    
        @Bean
        // @Conditional(ClassCondition.class)
        @ConditionOnClass("redis.clients.jedis.Jedis")
        public User user() {
            return new User();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这样只有导入了Jedis坐标,才会创建Bean

    Spring Boot已经提供了许多的ConditionalOnXxx注解,在Maven: org.springframework.boot:spring-boot-autoconfigure-2.7.1中,如下:

    在这里插入图片描述
    使用Spring Boot提供Conditional注解,测试如下,修改UserConfig.java

    package com.aiw.springbootcondition.config;
    
    import com.aiw.springbootcondition.pojo.User;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration // 标识为配置类
    public class UserConfig {
    
        @Bean
        // @Conditional(ClassCondition.class)
        // @ConditionOnClass("redis.clients.jedis.Jedis")
        public User user() {
            return new User();
        }
    
        @Bean
        @ConditionalOnProperty(name = "Aiw", havingValue = "test")
        public User user2() {
            return new User();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    修改主程序,如下:

    package com.aiw.springbootcondition;
    
    import com.aiw.springbootcondition.pojo.User;
    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) {
            // 启动Spring Boot的应用,返回Spring的IOC容器
            ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);
    
            Object user = context.getBean("user2", User.class);
            System.out.println(user);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    修改配置文件application.yml

    Aiw: test
    
    • 1

    启动项目,控制台输出如下:

    在这里插入图片描述

    若是在application.yml中找不到Aiw属性和其对应的值,则无法创建Bean

    小结

    1、自定义条件:

    ​ ① 定义条件类:自定义类实现Condition接口,重写 matches 方法,在 matches 方法中进行逻辑判断,返回 boolean值 。 matches 方法两个参数:

    ​ • context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。

    ​ • metadata:元数据对象,用于获取注解属性。

    ​ ② 判断条件: 在初始化Bean时,使用 @Conditional(条件类.class)注解

    2、SpringBoot 提供的常用条件注解:

    ​ • ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean

    ​ • ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean

    ​ • ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

    切换内置web服务器

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

    Maven: org.springframework.boot:spring-boot-autoconfigure-2.7.1中查看如下:

    在这里插入图片描述

    切换内置Web服务器,首先需要排除Tomcat

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
        
        <exclusions>
            <exclusion>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-tomcatartifactId>
            exclusion>
        exclusions>
    dependency>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-jettyartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    刷新依赖,重启项目,控制台如下:

    在这里插入图片描述

    切换其它服务器,方法类似。

    @Enable*注解

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

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

    答:不能。解决方法如下:

    1. 使用@ComponentScan扫描配置类所在的包

      @ComponentScan("com.aiw.config")
      
      • 1
    2. 使用@Import注解,加载类;这些类都会被Spring创建,并放入IOC容器

      @Import(Config.class)
      
      • 1
    3. 对@Import注解进行封装

      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Import(Config.class)
      public @interface EnableXxx{}
      
      • 1
      • 2
      • 3
      • 4
      • 5

    @Import注解

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

    ① 导入Bean

    修改主程序,如下:

    package com.aiw.springbootimport;
    
    import com.aiw.springbootimport.pojo.User;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Import;
    
    @SpringBootApplication
    @Import(User.class)
    public class SpringbootImportApplication {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(SpringbootImportApplication.class, args);
    
            // User user = context.getBean(User.class); // 这种获取不到
            User user = (User) context.getBean("user");
            System.out.println(user);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    使用这种方法,配置类上的@Configuration注解可以不需要了

    ② 导入配置类

    创建配置类

    package com.aiw.springbootimport.config;
    
    import com.aiw.springbootimport.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class UserConfig {
        @Bean
        public User user(){
            return new User();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    修改主程序,如下:

    package com.aiw.springbootimport;
    
    import com.aiw.springbootimport.config.UserConfig;
    import com.aiw.springbootimport.pojo.User;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Import;
    
    @SpringBootApplication
    @Import(UserConfig.class)
    public class SpringbootImportApplication {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(SpringbootImportApplication.class, args);
    
            User user = context.getBean(User.class);
            // User user = (User) context.getBean("user");     // 这种也可以获取到
            System.out.println(user);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ③ 导入 ImportSelector 实现类。一般用于加载配置文件中的类

    创建实现类,如下:

    package com.aiw.springbootimport.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[]{"com.aiw.springbootimport.pojo.User"};
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    字符串不是写死的,以后可以写到配置文件中去

    修改主程序,如下:

    package com.aiw.springbootimport;
    
    import com.aiw.springbootimport.config.MyImportSelector;
    import com.aiw.springbootimport.pojo.User;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Import;
    
    @SpringBootApplication
    @Import(MyImportSelector.class)
    public class SpringbootImportApplication {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(SpringbootImportApplication.class, args);
    
            // User user = context.getBean(User.class); // 这种获取不到
            User user = (User) context.getBean("user");    
            System.out.println(user);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    运行结果:
    在这里插入图片描述

    ④ 导入 ImportBeanDefinitionRegistrar 实现类。

    创建实现类

    package com.aiw.springbootimport.config;
    
    import com.aiw.springbootimport.pojo.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.beans.factory.support.BeanNameGenerator;
    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, BeanNameGenerator importBeanNameGenerator) {
            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
            registry.registerBeanDefinition("user",beanDefinition);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    修改主程序,如下:

    package com.aiw.springbootimport;
    
    import com.aiw.springbootimport.config.MyImportBeanDefinitionRegistrar;
    import com.aiw.springbootimport.pojo.User;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Import;
    
    @SpringBootApplication
    @Import(MyImportBeanDefinitionRegistrar.class)
    public class SpringbootImportApplication {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(SpringbootImportApplication.class, args);
    
            // User user = context.getBean(User.class); // 这种也可以获取到
            User user = (User) context.getBean("user");
            System.out.println(user);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    若报错,则在配置文件中添加如下:

    spring.main.allow-bean-definition-overriding=true
    
    • 1

    @EnableAutoConfiguration 注解

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

    自定义starter

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

    步骤:

    1. 创建 redis-spring-boot-autoconfigure 模块
    2. 创建 redis-spring-boot-starter 模块,依赖 redis-springboot-autoconfigure的模块
    3. 在 redis-spring-boot-autoconfigure 模块中初始化 Jedis 的 Bean。并定义META-INF/spring.factories 文件
    4. 在测试模块中引入自定义的 redis-starter 依赖,测试获取 Jedis 的Bean,操作 redis。

    SpringBoot 监听机制

    Java 监听机制

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

    Java中的事件监听机制定义了以下几个角色:

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

    SpringBoot 监听机制

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

    ApplicationContextInitializer、SpringApplicationRunListener、CommandLineRunner、ApplicationRunner

    创建Spring Boot(2.7.2)工程,分别创建4个实现类:
    MyApplicationContextInitializer.java

    package com.aiw.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");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    MySpringApplicationRunListener.java

    package com.aiw.springbootlistener.listener;
    
    import org.springframework.boot.ConfigurableBootstrapContext;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.SpringApplicationRunListener;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.core.env.ConfigurableEnvironment;
    
    import java.time.Duration;
    
    public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    
        public MySpringApplicationRunListener(SpringApplication application, String[] args){}
        
        @Override
        public void starting(ConfigurableBootstrapContext bootstrapContext) {
            System.out.println("starting...项目启动中");
        }
    
        @Override
        public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, 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, Duration timeTaken) {
            System.out.println("started...上下文对象加载完成");
        }
    
        @Override
        public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
            System.out.println("ready...项目启动完成,开始运行");
        }
    
        @Override
        public void failed(ConfigurableApplicationContext context, Throwable exception) {
            System.out.println("failed...项目启动失败");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    SpringApplicationRunListener的实现类必须提供构造方法,否则报错;并且不能使用@Component自动注入

    MyCommandLineRunner.java

    package com.aiw.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.toString(args));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    MyApplicationRunner.java

    package com.aiw.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.toString(args.getSourceArgs()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    启动项目,目前是没有任何参数。如下:

    在这里插入图片描述

    点击环境配置->修改选项->勾选程序实参,输入name=Aiw如下:

    在这里插入图片描述

    再次启动项目,如下:

    在这里插入图片描述

    可以发现,始终有两个未生效;在resources目录下新建META-INF/spring.factories文件,内容如下:

    org.springframework.context.ApplicationContextInitializer=com.aiw.springbootlistener.listener.MyApplicationContextInitializer
    org.springframework.boot.SpringApplicationRunListener=com.aiw.springbootlistener.listener.MySpringApplicationRunListener
    
    • 1
    • 2

    键是对应接口的全路径名,值是自定义实现类的引用

    再次启动项目,如下:

    在这里插入图片描述

    SpringBoot 启动流程分析

    启动流程

    在这里插入图片描述

    替换默认banner

    将以下内容保存为banner.txt,放于src/main/resources/banner.txt

                       _ooOoo_  
                      o8888888o  
                      88" . "88  
                      (| -_- |)  
                       O\ = /O  
                   ____/`---'\____  
                 .   ' \\| |// `.  
                  / \\||| : |||// \  
                / _||||| -:- |||||- \  
                  | | \\\ - /// | |  
                | \_| ''\---/'' | |  
                 \ .-\__ `-` ___/-. /  
              ___`. .' /--.--\ `. . __  
           ."" '< `.___\_<|>_/___.' >'"".  
          | | : `- \`.;`\ _ /`;.`/ - ` : | |  
            \ \ `-. \_ __\ /__ _/ .-` / /  
    ======`-.____`-.___\_____/___.-`____.-'======  
                       `=---='  
    
    .............................................  
             佛祖保佑             永无BUG 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    启动项目,可以看到默认banner已被替换。

    在这里插入图片描述

    SpringBoot 监控

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

    SpringBoot 监控使用

    ① 导入依赖坐标

    创建Spring Boot(2.7.2)项目,并勾选如下依赖:
    在这里插入图片描述

    也可以手动导入

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-actuatorartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ② 启动项目,访问http://localhost:8080/actuator

    在这里插入图片描述

    访问http://localhost:8080/actuator/health,默认不显示详细信息

    在这里插入图片描述

    在配置文件中添加如下:

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

    重新启动项目,如下:

    在这里插入图片描述

    若引入redis坐标:

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-redisartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    重新启动项目,如下:

    在这里插入图片描述

    再次修改配置文件

    # 开启健康检查的完整信息
    management.endpoint.health.show-details=always
    
    # 将所有的监控endpoint暴露出来
    management.endpoints.web.exposure.include=*
    
    • 1
    • 2
    • 3
    • 4
    • 5

    重新启动项目,如下:

    在这里插入图片描述

    说明:

    在这里插入图片描述

    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

    在这里插入图片描述

    或者手动导入:

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>de.codecentricgroupId>
        <artifactId>spring-boot-admin-starter-serverartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ​ ③ 在引导类上启用监控功能@EnableAdminServer

    package com.aiw.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);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在配置文件中添加如下:

    server.port=9000
    
    • 1

    admin-client:

    ​ ① 创建 admin-client 模块

    ​ ② 导入依赖坐标 admin-starter-client

    在这里插入图片描述

    或者手动导入:

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>de.codecentricgroupId>
        <artifactId>spring-boot-admin-starter-clientartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ​ ③ 配置相关信息:server地址等

    在配置文件中添加如下:

    # 执行admin.server地址
    spring.boot.admin.client.url=http://localhost:9000
    
    # 开启健康检查的完整信息
    management.endpoint.health.show-details=always
    
    # 将所有的监控endpoint暴露出来
    management.endpoints.web.exposure.include=*
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ​ ④ 启动server和client服务,访问server

    在浏览器输入http://localhost:9000/

    在这里插入图片描述

    点击在线项,页面如下:

    在这里插入图片描述

    IDEA也提供了快捷功能,如下:

    在这里插入图片描述

    SpringBoot 项目部署

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

    ① jar包(官方推荐)

    ② war包

    jar包

    新建SpringBoot(2.7.2)项目,勾选Web依赖坐标,并创建简单控制器,如下:

    package com.aiw.springbootdeploy.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/user")
    public class UserController {
        @RequestMapping(value = "/all", method = RequestMethod.GET)
        public String all() {
            return "success";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在IDEA中打开Maven界面,双击package

    在这里插入图片描述

    出现以下界面,则打包成功:
    在这里插入图片描述

    打包位置位于target目录下:

    在这里插入图片描述

    打开所在文件夹,如下:
    在这里插入图片描述

    按住shift+鼠标右键,点击在此处打开Powershell窗口,输入如下命令:
    在这里插入图片描述

    回车,即可启动服务:
    在这里插入图片描述

    在浏览器输入http://localhost:8080/user/all

    在这里插入图片描述

    war包

    修改pom.xml的打包方式为war

    <packaging>warpackaging>
    
    • 1

    修改主程序,如下:

    package com.aiw.springbootdeploy;
    
    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 builder.sources(SpringbootDeployApplication.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    排除内置的Tomcat

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-tomcatartifactId>
            exclusion>
        exclusions>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    pom.xml声明使用外部Tomcat服务器

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-tomcatartifactId>
        <scope>providedscope>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    若觉得打包的名称不好看,可以指定名称,在pom.xmlbuild标签下添加finalName即可:

    <build>
        <finalName>springbootfinalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这样打包的名称就是springboot了

    重新打包,如下:

    在这里插入图片描述

    将生成的war包放于外部的Tomcat的webapps目录下,如下:
    在这里插入图片描述

    启动外部Tomcat,双击startup.bat,运行项目之后Tomcat会自动解包,如下:

    在这里插入图片描述

    再在浏览器上访问http://localhost:8080会出现外部Tomcat的信息,如下:

    在这里插入图片描述

    此时再访问http://localhost:8080/user/all,则找不到路径,如下:

    在这里插入图片描述

    需要再加一层目录,也就是项目的打包名称,即http://localhost:8080/springboot/user/all

    实测,不知为何加上项目名后,还是报404错误,难道是新版本有改动?

    注意,使用war包方式,若还是在配置文件中修改端口地址,则是不生效的,因为此时war包是使用外部服务器;需要到外部服务器配置文件中去改。

  • 相关阅读:
    Unity三种物体溶解方法
    古早软件 vim的使用
    ModbusTCP、TCP/IP都走网线,一样吗?
    VirtualBox 中 Ubuntu 无法打开terminal
    QT环境下配置Assimp库(MinGW编译器)
    Linux Bond 以及Mode 6实验
    设计模式---单例模式
    项目经理面试经典问题大揭秘:聪明回答,轻松获得心仪职位!
    在Linux上开启文件服务,需要安装并配置Samba
    基于springboot实现大学生就业服务平台系统项目【项目源码】
  • 原文地址:https://blog.csdn.net/qq_45917176/article/details/126185400