static使用在Class内部类上
在PersonConfig
里增加一个静态内部类:
@Configuration(proxyBeanMethods = false) public class PersonConfig { ... // 同上 // 非静态内部类 @Configuration(proxyBeanMethods = false) private class InnerClass { public InnerClass() { System.out.println("内部配置类InnerClass构造器被执行..."); } @Bean public Person innerPerson() { System.out.println("@Bean -> innerPerson执行..."); return new Person(); } } // static静态内部类 @Configuration(proxyBeanMethods = false) private static class StaticInnerClass { public StaticInnerClass() { System.out.println("静态内部配置类StaticInnerClass构造器被执行..."); } @Bean public Person staticInnerPerson() { System.out.println("@Bean -> staticInnerPerson执行..."); return new Person(); } } }
其它不变,再次运行测试程序,控制台输出:
... 配置类Config构造器被执行... 配置类PersonConfig构造器执行... @Bean -> family执行... @Bean -> staticFamily执行... 静态内部配置类StaticInnerClass构造器被执行... @Bean -> staticInnerPerson执行... 内部配置类InnerClass构造器被执行... @Bean -> innerPerson执行... @Bean -> son执行... @Bean -> father执行...
结论:
@Configuration(外层)配置类的初始化顺序依旧是按照AnnotationConfigApplicationContext的定义顺序来的
对于内部类的@Configuration的初始化(不管是静态还是非静态),也依旧是外部的@Configuration完成后才行
内部类里的@Bean的优先级均高于外层定义的@Bean,同时可以看到static静态内部类能够提升优先级,它比非静态内部类的优先级还高
内部类有限原则它只作用于本@Configuration类,也就是说仅在本主类内提升优先级。另外若出现多个内部类,按照定义顺序执行(static永远高于非static哦)
内部类的访问权限无所谓,private都行。
Spring Boot环境
在Spring Boot下会更加关心配置类和@Bean的执行顺序:因为Spring Boot内置了非常多的@Configuration以及@Bean,均是通过扫描的方式“收集”而不能Diy控制,因此它需要提供指定配置类顺序的能力。
控制@Configuration配置类顺序
关于Spring Boot下控制@Configuration的顺序,我们会使用@AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder这三个注解去控制,关于它们的正确使用姿势,请参阅:你了解Spring Boot的自动配置吗?为何我的@AutoConfigureBefore注解不生效?
通过static提升优先级的示例
在Spring Boot的自动配置里,有非常多的通过static提升优先级的case,这里我找了个熟悉的例子进行说明:
@Configuration(proxyBeanMethods = false) public class FeignClientsConfiguration { @Bean @Scope("prototype") @ConditionalOnMissingBean public Feign.Builder feignBuilder(Retryer retryer) { return Feign.builder().retryer(retryer); } // 当Classpath里存在HystrixCommand、HystrixFeign等类时,就自动和Hystrix集成 @Configuration(proxyBeanMethods = false) @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(); } } }
这是一个典型案例:当然类路径存在Hystrix时,自动使用带有熔断功能的HystrixFeign.builder构建器,否则使用的默认的Feign.builder构建器。此处利用的就是内部类具有更高优先级,因此可以先去执行判断~
控制@Bean顺序
同Spring Framwork。
@DependsOn和static提升优先级的区别
其实把他俩放在一起比较其实蛮牵强的,根本不是同一回事嘛。但是在提升优先级方面,此处絮叨两句:
- @DependsOn强调的是Bean与Bean之间的依赖关系。如:A @DependsOn B表示,只有当B初始化完成了才会去初始化A。这里所谓的Bean可以是任何Bean:包括@Bean、@Component、@Configuration等一切形式
- static它主要运用在@Configuration配置文件内来提升优先级,这种优先级体现在:内部类里的@Bean比外部类会先加载,static静态内部类的@Bean又会比普通内部类的@Bean先加载
总结
本文主要讲解了Spring、Spring Boot中对配置文件以及Bean的加载顺序问题,虽说我们并不能绝对的控制Bean的顺序,但我们能采取一定的措施,如使用@DependsOn或static来提高某些Bean的优先级或者相对顺序,这便也能解决我们的需求。在实际使用中,我们的确并不需要控制每个Bean的顺序,而只需操控其相对顺序即可。
有的人说不能控制Bean的顺序是Spring容器在设计时疏忽的一点(究其原因是底层使用了Set的结构,因此无法保证顺序),我也在一定程度上表示赞同。但是它提供了形如@Order、@DependsOn、static来“补救”,我觉得这个“小缺点”已然无伤大雅了。
当然,这并不能算作Spring设计上的缺陷。但是它的底层存储如果使用更为抽象的Collection我觉得是更好的选择,你认为呢?