• Spring boot再来一遍


    spring-boot-starter-parent

    • 作为spring boot快速构建spring工程所依赖包的模板
    • spring-boot-starter-parent的继承了spring-b
    • boot-dependencies(2.1.8 Release)
    • dependencies中定义了spring boot快速构建所需要的依赖包及版本信息
    • dependencies中有版本锁定dependencManagement版本锁定,定义了一个最优的版本搭配套装,如果一个工程继承了spring-booot-dependencies,那么该工程即可以不用配置依赖包版本

    springboot启动流程

    • 在SpringApplication中,springboot核心启动代码为new SpringApplication(primarySource).run(args),其中:
      • 实例化一个SpringApplication是为了加载各种配置信息
      • 实例化对象的.run方法,是为了初始化容器
        在这里插入图片描述

    spring-boot-starter-web

    • spring-boot-starter-web是spring-boot-start-parent中已经定义好的坐标和版本信息
    • 业务工程中,只需要指定spring-boot-starter-web的坐标即可,不需要再指定版本

    artifactid

    • springboot自己提供的依赖,一般功能名称在最后,例如spring-boot-starter-jdbc
    • 而第三方提供的依赖,一般功能名字在最前,例如mybatis-spring-boot-starter

    spring配置文件

    • 优先级顺序:application.properties>application.yml>application.yaml
    • 如果在写yml过程中没有提示联想信息,需要引入dependencies-processor依赖
    spring-boot-configuration-processor
    
    • yaml中定义数组:
    address:
    	- beijing
    	- tianjin
    address: [beijing,tianjin]
    
    user:
     name: zh
     age: 18
     phones:
      - 15522222222
      - 15551111111
    
    • 程序引用配置的方式:
    // 1、@value注解
    @Value("${address[0]}")
    private String address;// beijing
    
    // 2.Environment(org.springframework.core.env)
    @Autowired
    private Environmen env;
    public void print(){
    	sout(env.getProperty("address[0]"));// beijing
    }
    
    // 3、@ConfigurationProperties,实体类映射配置,一定注意层级关系,如果有必要,需要加prefix 
    @Component
    @ConfigurationProperties(prefix = "user")
    public class user(){
    	private String name;
    	private Int age;
    	private String[] phones;
    
    	// 省略get set方法
    }
    

    @Condition

    • 按照条件来判断,满足条件的类会被容器注册为bean
    • 基本用法:
    // 1.define a class implements Conditon, override 'matches' method and return true or false after your check statement
    public class ConditionCheck implements Condition(){
    	@Override
    	public boolean matches(CondtionContext context, AnnotatedTypeMetadta metadata){
    		// check statement
    		return false;
    	}
    }
    
    // 2.mark the annotation on the class you want to control
    @Configuration
    public class CustomerizedConfig{
    	@Bean
    	@Condition(ConditionCheck.class)
    	pubic Config config(){
    		return new Config();
    	}
    }
    
    • 也可以基于元注解,自定义一个注解,进行条件解析
    // 1.define customerize annotation 
    @Target({ElementType.TYPE, ElementType.METHOD})// 元注解:指定本注解范围
    @Retention(RetentionPolicy.RUNTIME)//元注解:指定生效时间
    @Documented//元注解:是否生成javadoc
    @Condition(ConditionCheck.class)// 引用Condition注解
    public @interface MyCondtion{
    	String value();// 这里的值,会传给ConditionCheck.class中,可以通过metadata中获取value
    }
    
    // 2.mark the annotation on the class you want to control
    @Configuration
    public class CustomerizedConfig{
    	@Bean
    	@MyCondtion("abc")// abc就会传给MyCondtion的value属性中,然后再在ConditionCheck.class中加工判断,返回boolean决定本方法中的Config类是否被加载到bean容器中
    	pubic Config config(){
    		return new Config();
    	}
    }
    
    • Condition相关的还有很多注解:
      • @ConditionalOnClass // 判断环境中是否又对应的文件
      • @ConditionalOnProperty // 判断配置文件中是否有对应属性值
      • @ConditionalOnMissingBean // 判断环境中没有对应的bean
    • matches方法两个参数:
      • CondtionContext context:上下文对象,可获取属性值,获取类加载器,获取BeanFactory等
      • AnnotatedTypeMetadta metadata:元数据对象,用于获取注解属性。

    @Enable开头的注解

    • spring boot中的enbale开头的注解,用于动态启动某些功能,其内部都是实用@import导入配置类,进行bean的动态加载。
    • @ComponentScan是@SpringBootApplication中的注解,其作用是扫描该类同目录及其子目录下所有的bean
    • Enable开头注解的由来,举例说明下演变过程:
    // 案例:如果项目A如果想获取B项目的test类,怎么获取?
    // 而且B中的@ComponentScan注解还扫描不到test类
    // 方法一,在项目A中使用@ComponentScan添加该类的扫描:
    @SpringBootApplication
    @Component("com.test")
    public class AprojectAapplication{
    	xxx
    	context.getBean("test");// 可以获取到
    }
    
    // 但是方法一比较笨重,因为第三方test的路径,使用方法二,在A项目使用Import注解:
    @SpringBootApplication
    @Import(test.class)
    public class AprojectAapplication{
    	xxx
    	context.getBean("test");// 可以获取到
    }
    
    // 方法二也不是最好的方法,使用方法三,在B项目进行封装个Enable开头的注解:
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(test.class)
    public @interface EnableTest{
    }
    
    // 然后再B项目直接饮用EnableTest注解,此处也是验证到了Enable开头注解的作用和由来
    @SpringBootApplication
    @EnableTest
    public class AprojectAapplication{
    	xxx
    	context.getBean("test");// 可以获取到
    }
    

    @Import

    • 被@Import导入的类,会被加载到IOC容器中
    • @Import导入的四种方式:
      • 直接导入Bean
      • 导入配置类
    @Configuration
    public class Config{
    	@Bean
    	public Test test(){
    		return new Test();
    	}
    	@Bean
    	public Test2 test2(){
    		return new Test2();
    	}
    }
    
    * 导入ImportSelector实现类(常用于加载配置文件中的类)
    
    // 先在项目B声明一个ImportSelector实现类
    public TestImportSelector implements ImportSelector{
    	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata ){
    		return String[]{"com.Test", "com.Test2"};
    	}
    }
    
    // 再在项目A中import
    @SpringBootApplication
    @Import(TestImportSelector.class)
    public class AprojectAapplication{
    	xxx
    	context.getBean("test");// 可以获取到
    }
    
    
    * 导入ImportBeanDefinitionRegistrar实现类
    
    
    public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar{
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Test.class).getBeanDefinition();
            registry.registerBeanDefinition("test", beanDefinition);
    
        }
    }
    

    @EnableAutoConfiguration

    • @EnableAutoConfiguration注解内部使用@Import加载配置类
    • 工程会根据依赖第三方包中的META/spring.factories配置,扫描配置类,当SpringBoot应用时,会自动初始化这些bean(关于spring.factories的意义,点击这篇文章可以了解更多)
    • 第三方的bean也是依赖conditon条件进行初始化的

    模拟redis自定义一个starter,构建一个第三方包

    1. 定义一个redis-speeder-autoconfig,用来配置和模拟链接redis
    2. 定义一个redis-speeder-starter,引用redis-spring-boot-autoconfigure,用来整合和包装
    3. 使用META-INF/spring.factories,控制容器是否加载jedis的bean,关于
    4. 测试starter,测试获取jedis的bean
    // 1、新建redis-speeder-autoconfig模块,用来配置和模拟链接redis
    // 1.1、定义Redis.config类,用来配置redis和读取用户自定义redis配置
    package com.entity;
    
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    /**
     * 这个配置类是为了让引用本包的用户自定义配置host和port
     */
    @Component
    // ConfigurationProperties是绑定用户定义的配置文件,redis开头的配置即可,可以是.properties/.yaml等
    @ConfigurationProperties(prefix = "redis")
    // 避免和META-INF/spring.factories
    @ConditionalOnMissingBean(RedisConfig.class)
    public class RedisConfig{
        private String host = "localhost";// 默认localhost,如果用户配置了redis.host,则会覆盖本配置
        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;
        }
    }
    
    // 1.2、定义RedisMock,用来模拟redis服务
    package com.entity;
    
    /**
     * 模拟redis的启动
     */
    public class RedisMock {
        public RedisMock(RedisConfig rc){
            System.out.println("redis initint...");
            System.out.println("redis mocked host:"+rc.getHost());
            System.out.println("redis mocked port:"+rc.getPort());
            System.out.println("redis inited! ");
        }
        public void print(){
            System.out.println("redis server is running");
        }
    }
    
    // 1.3、加载Redis服务类bean至ioc容器中
    package com.speeder;
    
    import com.entity.RedisConfig;
    import com.entity.RedisMock;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    // 加载配置类RedisConfig,用来读取redis配置或者用户定义的redis配置
    @EnableConfigurationProperties(RedisConfig.class)
    public class RedisAutoConfiguration {
    
        @Bean
        public RedisMock redisMock(RedisConfig RedisConfig){
    
            return new RedisMock(RedisConfig);
        }
    }
    
    
    // 1.4、定义META-INF/spring.factories,用来加载RedisConfig类至ioc容器中
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      com.entity.RedisConfig
    
    
    // 2、定义redis-speeder-starter模块,仅用来整合和包装redis-speeder-autoconfig模块
            <dependency>
                <groupId>org.example</groupId>
                <artifactId>redis-speeder-starter</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
    
    // 3、测试,
    // 3.1定义redis-speeder-test模块,用来测试starter的配置
    package com.speeder;
    
    import com.entity.RedisMock;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    
    @SpringBootApplication
    public class TestApplication {
        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(TestApplication.class, args);
            // context.getBean("RedisConfig");
            RedisMock redisMock = (RedisMock)context.getBean("redisMock");
            redisMock.print();
            System.out.println("bean = " + redisMock);
        }
    }
    // 3.2、定义配置类resource/application.properties
    redis.host=233.3.3.3
    redis.port=1111
    
    // 测试结果:
    // 在启动过程中,可以得到手工打印的内容:
    2022-09-24 17:06:03.256  INFO 1588 --- [           main] com.speeder.TestApplication              : Starting TestApplication using Java 1.8.0_231 on DESKTOP-E7BNK32 with PID 1588 (E:\mycode\spring-study\spring-boot\redis-speeder-test\target\classes started by zhaoheng in E:\mycode\spring-study\spring-boot)
    2022-09-24 17:06:03.256  INFO 1588 --- [           main] com.speeder.TestApplication              : No active profile set, falling back to 1 default profile: "default"
    2022-09-24 17:06:04.257  INFO 1588 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
    2022-09-24 17:06:04.272  INFO 1588 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2022-09-24 17:06:04.272  INFO 1588 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.65]
    2022-09-24 17:06:04.397  INFO 1588 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2022-09-24 17:06:04.397  INFO 1588 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1094 ms
    redis initint...
    redis mocked host:233.3.3.3
    redis mocked port:1111
    redis inited! 
    2022-09-24 17:06:04.678  INFO 1588 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    2022-09-24 17:06:04.694  INFO 1588 --- [           main] com.speeder.TestApplication              : Started TestApplication in 1.928 seconds (JVM running for 3.405)
    redis server is running
    bean = com.entity.RedisMock@70325d20
    
    

    SpringBoot Actuator监控

    • 引入依赖启动,即可创建监控台
       <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>
    
    • 访问监控内的相关资源:
      1. 访问监控台:localhost:8080/actuator,会返回控制台所有地址导航信息
      2. 访问配置信息:localhost:8080/actuator/info等
      3. 健康检查:localhost:8080/actuator/health,可以查看项目是否在正常运行,也可以检查其他第三方依赖的健康状况,例如redis、数据库等
      4. 开启actuator所有监控:application.properties中加入management.endpoints.web.exposure.include=*
      5. 查看ioc容器中所有的bean:localhost:8080/actuator/bean
      6. 查看项目的环境配置信息:localhost:8080/actuator/env
      7. 查看所有的接口请求路径:localhost:8080/actuator/mappings
    {
        "_links": {
            "self": {
                "href": "http://localhost:8080/actuator",
                "templated": false
            },
            "health-component": {
                "href": "http://localhost:8080/actuator/health/{component}",
                "templated": true
            },
            "health-component-instance": {
                "href": "http://localhost:8080/actuator/health/{component}/{instance}",
                "templated": true
            },
            "health": {
                "href": "http://localhost:8080/actuator/health",
                "templated": false
            },
            "info": {
                "href": "http://localhost:8080/actuator/info",
                "templated": false
            }
        }
    }
    
  • 相关阅读:
    痞子衡嵌入式:浅析IAR下调试信息输出机制之硬件UART外设
    西门子CT重建算法
    Linux虚拟地址空间
    llama factory 大数据量下训练失败
    ‘setuptools‘ is a dependency of conda and cannot be removed from
    zabbix监控TCP连接个数
    SpringBoot bbs(3~4) 过度创作总结。
    深入理解Docker自定义网络:构建高效的容器网络环境
    1109 Group Photo
    代码随想录 Day7 字符串1 LeetCode T344反转字符串 T541 反转字符串II 151翻转字符串的单词
  • 原文地址:https://blog.csdn.net/z591391960/article/details/126923574