static关键字有何魔法?竟让Spring Boot搞出那么多静态内部类(中)

简介: static关键字有何魔法?竟让Spring Boot搞出那么多静态内部类(中)

看到这个结果,如果你就过早的得出结论:静态内部类优先级高于外部类,那么就太随意了,图样图森破啊。大胆猜想,小心求证 应该是程序员应有的态度,那么继续往下看,在此基础上我新增加一个静态内部类:


@Configuration
class OuterConfig {
    OuterConfig() {
        System.out.println("OuterConfig init...");
    }
    @Bean
    static Parent parent() {
        return new Parent();
    }
    @Configuration
    private static class PInnerConfig {
        PInnerConfig() {
            System.out.println("PInnerConfig init...");
        }
        @Bean
        Son son() {
            return new Son();
        }
    }
    @Configuration
    private static class InnerConfig {
        InnerConfig() {
            System.out.println("InnerConfig init...");
        }
        @Bean
        Daughter daughter() {
            return new Daughter();
        }
    }
}


我先解释下我这么做的意图:


1.增加一个字母P开头的内部类,自然顺序P在O(外部类)后面,消除影响


2.P开头的内部类在源码摆放顺序上故意放在了I开头的内部类的上面,同样为了消除字母表顺序带来的影响

  1. 目的:看看是按照字节码顺序,还是字母表顺序呢?


3.PInnerConfig里面的@Bean实例为Son,字母表顺序是三者中最为靠后的,但字节码却在中间,这样也能够消除影响


运行程序,结果输出:


InnerConfig init...
PInnerConfig init...
OuterConfig init...
Daughter init...
son init...
Parent init...


结果细节:外部类貌似总是滞后于内部类初始化;同一类的多个内部类之间顺序是按照字母表顺序(自然排序)初始化而非字节码顺序;@Bean方法的顺序依照了类的顺序


请留意本结果和上面结果是否有区别,你应该若有所思。


这是单.java文件的case(所有static类都在同一个.java文件内),接下来我在同目录下增加 2个.java文件(请自行留意类名第一个字母,我将不再赘述我的设计意图):


// 文件一:
@Configuration
class A_OuterConfig {
    A_OuterConfig() {
        System.out.println("A_OuterConfig init...");
    }
    @Bean
    String a_o_bean(){
        System.out.println("A_OuterConfig a_o_bean init...");
        return new String();
    }
    @Configuration
    private static class PInnerConfig {
        PInnerConfig() {
            System.out.println("A_OuterConfig PInnerConfig init...");
        }
        @Bean
        String a_p_bean(){
            System.out.println("A_OuterConfig a_p_bean init...");
            return new String();
        }
    }
    @Configuration
    private static class InnerConfig {
        InnerConfig() {
            System.out.println("A_OuterConfig InnerConfig init...");
        }
        @Bean
        String a_i_bean(){
            System.out.println("A_OuterConfig a_i_bean init...");
            return new String();
        }
    }
}
// 文件二:
@Configuration
class Z_OuterConfig {
    Z_OuterConfig() {
        System.out.println("Z_OuterConfig init...");
    }
    @Bean
    String z_o_bean(){
        System.out.println("Z_OuterConfig z_o_bean init...");
        return new String();
    }
    @Configuration
    private static class PInnerConfig {
        PInnerConfig() {
            System.out.println("Z_OuterConfig PInnerConfig init...");
        }
        @Bean
        String z_p_bean(){
            System.out.println("Z_OuterConfig z_p_bean init...");
            return new String();
        }
    }
    @Configuration
    private static class InnerConfig {
        InnerConfig() {
            System.out.println("Z_OuterConfig InnerConfig init...");
        }
        @Bean
        String z_i_bean(){
            System.out.println("Z_OuterConfig z_i_bean init...");
            return new String();
        }
    }
}


运行程序,结果输出:


A_OuterConfig InnerConfig init...
A_OuterConfig PInnerConfig init...
A_OuterConfig init...
InnerConfig init...
PInnerConfig init...
OuterConfig init...
Z_OuterConfig InnerConfig init...
Z_OuterConfig PInnerConfig init...
Z_OuterConfig init...
A_OuterConfig a_i_bean init...
A_OuterConfig a_p_bean init...
A_OuterConfig a_o_bean init...
Daughter init...
son init...
Parent init...
Z_OuterConfig z_i_bean init...
Z_OuterConfig z_p_bean init...
Z_OuterConfig z_o_bean init...


这个结果大而全,是有说服力的,通过这几个示例可以总结出如下结论:


1.垮.java文件 (垮配置类)之间的顺序,是由自然顺序来保证的(字母表顺序)

   1.如上:下加载A打头的配置类(含静态内部类),再是O打头的,再是Z打头的


2.同一.java文件内部,static静态内部类优先于外部类初始化。若有多个静态内部类,那么按照类名自然排序初始化(并非按照定义顺序哦,请务必注意)

   1.说明:一般内部类只可能与外部类“发生关系”,与兄弟之间不建议有任何联系,否则顺序控制上你就得当心了。毕竟靠自然顺序去保证是一种弱保证,容错性太低


3.同一.java文件内,不同类内的@Bean方法之间的执行顺序,保持同2一致(也就说你的@Bean所在的@Configuration配置类先加载,那你就优先被初始化喽)

同一Class内多个@Bean方法的执行顺序,上篇文章static关键字真能提高Bean的优先级吗?答:真能 就已经说过了哈,请移步参见


总的来说,当static标注在class类上时,在同.java文件内它是能够提升优先级的,这对于Spring Boot的自动配置非常有意义,主要体现在如下两个方法:


  • static静态内部类配置优先于外部类加载,从而静态内部类里面的@Bean也优先于外部类的@Bean先加载
  • 既然这样,那么Spring Boot自动配置就可以结合此特性,就可以进行具有优先级的@Conditional条件判断了。这里我举个官方的例子,你便能感受到它的魅力所在:
@Configuration
public class FeignClientsConfiguration {
  ...
  @Bean
  @Scope("prototype")
  @ConditionalOnMissingBean
  public Feign.Builder feignBuilder(Retryer retryer) {
    return Feign.builder().retryer(retryer);
  }
  @Configuration
  @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
  protected static class HystrixFeignConfiguration {
    @Bean
    @Scope("prototype")
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "feign.hystrix.enabled")
    public Feign.Builder feignHystrixBuilder() {
      return HystrixFeign.builder();
    }
  }
}


因为HystrixFeign.builder()它属于静态内部类,所以这个@Bean肯定是优先于外部的Feign.builder()先加载的。所以这段逻辑可解释为:优先使用HystrixFeign.builder()(若条件满足),否则使用Feign.builder().retryer(retryer)作为兜底。通过此例你应该再一次感受到Bean的加载顺序之于Spring应用的重要性,特别在Spring Boot/Cloud下此特性尤为凸显。


你以为记住这几个结论就完事了?不,这明显不符合A哥的逼格嘛,下面我们就来继续挖一挖吧。

相关文章
|
13天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
25 2
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
56 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
64 2
|
5月前
|
运维 Java 关系型数据库
Spring运维之boot项目bean属性的绑定读取与校验
Spring运维之boot项目bean属性的绑定读取与校验
54 2
|
5月前
|
存储 运维 Java
Spring运维之boot项目开发关键之日志操作以及用文件记录日志
Spring运维之boot项目开发关键之日志操作以及用文件记录日志
66 2
|
5月前
|
Java Maven
springboot项目打jar包后,如何部署到服务器
springboot项目打jar包后,如何部署到服务器
440 1
|
5月前
|
XML 运维 Java
Spring运维之boot项目打包jar和插件运行并且设置启动时临时属性和自定义配置文件
Spring运维之boot项目打包jar和插件运行并且设置启动时临时属性和自定义配置文件
55 1
|
5月前
springboot2.4.5使用pagehelper分页插件
springboot2.4.5使用pagehelper分页插件
159 0
|
5月前
|
缓存 运维 Java
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
49 0
|
6月前
|
安全 Java 应用服务中间件
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置
69 0
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置
下一篇
无影云桌面