SpringBoot自动装配定义先后顺序失效原因极其解析

1、场景分析

遇到的场景:
最近写定义依赖时,需要结合SpringMvcWebMvcConfigurationSupport扩展异常解析器方法extendHandlerExceptionResolvers

	@Bean
	public HandlerExceptionResolver handlerExceptionResolver(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
		List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
		configureHandlerExceptionResolvers(exceptionResolvers);
		if (exceptionResolvers.isEmpty()) {
			addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
		}
		extendHandlerExceptionResolvers(exceptionResolvers);
		HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
		composite.setOrder(0);
		composite.setExceptionResolvers(exceptionResolvers);
		return composite;
	}

其中extendHandlerExceptionResolvers方法提供了可继承的接口,让开发者能够添加自定义的异常解析器放到HandlerExceptionResolverComposite中供dispatchServlet解析异常

1.1、问题总结

自定义的异常解析器配置类继承WebMvcConfigurationSupport类重写extendHandlerExceptionResolvers方法后,按照开放接口的原理,我们的异常解析器会添加到HandlerExceptionResolverComposite列表中,但是实际上并非如此。

  1. 开发者自定义的装配类和WebMvcConfigurationSupport引用的jar包中装配类顺序
  2. 解决方案一:使用@AutoConfigureBefore@AutoConfigureAfter@AutoConfigureOrder注解指定加载顺序
  3. 解决方案二:使用静态内部装配类提前加载

2、使用@AutoConfigureBefore@AutoConfigureAfter@AutoConfigureOrder注解指定加载顺序

SpringBoot下可以通过@Configuration自动扫描配置类和spring.factories来加载配置类,但这两种方式都无法控制加载顺序。

此时,可通过在配置类上增加@AutoConfigureAfter 、 @AutoConfigureBefore和@AutoConfigureOrder来控制配置文件加载的相对顺序。

SpringBoot的自动配置是通过spring.factories来指定的,它的优先级最低,加载时间最晚,spring.factories中的配置类顺序不代表实际加载顺序。可结合 @AutoConfigureAfter 和 @AutoConfigureBefore注解控制配置类的相对加载顺序。

通过@Configuration和@ComponentScan扫描加载的配置类,一般是我们自定义的配置类,这部分配置类优先级最高,加载时间最早,在加载spring.factories配置类前加载,但加载顺序不定。
这里就存在另一个易错点。简单的理解,当配置类在Spring扫描路径里面(scanBasePackages)会优先解析,后面在通过ImportSelector(spring.factories加载就是通过实现这个接口加载的配置类)加载进来的配置类就不会处理了,相当于一个类有两种加载方式,谁先加载谁就厉害。。。这里加载都会调用到processConfigurationClass()方法,这个下面会说!!!!

空口无凭上菜:ConfigurationClassParser–>doProcessConfigurationClass()方法加载顺序是@ComponentScan(扫描文件路径,路径里面元注解为@Component(@Cofiguration元注解也是@Component)都会被扫描到)—>加载@Import注解(配合ImportSelector接口)—>加载 @ImportResource—>加载@Bean—>…
大致顺序理清楚了。
也就是:通过spring.factories加载的配置类优先级更低,我们自定义的装配类最后才会加载

2.2、@AutoConfigureXX注解失效原因总结

extendHandlerExceptionResolvers方法在WebMvcConfigurationSupport加载的时候已经执行过了,由于加载顺序问题,那么我们自己的装配类中重写方法,将无法被调用;所以这就是@AutoConfigureBefore@AutoConfigureAfter@AutoConfigureOrder注解无法生效的原因,不适用很多场景

3、使用静态内部装配类提升加载顺序

这也是小编使用的方法,这种场景在纯Spring环境下我们几乎遇不见,缘由是在Spring下所有的配置文件都是我们手动确定和编写,所以“哪些能写、哪些不能写,哪些在前,哪些在后”均是确定的,由我们程序员自行控制。该场景在Spring Boot场景下被大量用到
在这里插入图片描述总结如下:

  • static加在bean注册方法上

1、 @Configuration配置类最优先被初始化,才会继续初始化其里面的@Bean;若有多个 @Configuration配置类,顺序由你构造AnnotationConfigApplicationContext时传入的顺序为准(若是被scan扫描进去的,则无序)


2、 @Bean方法上加static成为静态方法,并不能提升此Bean的优先级
主要是因为@Bean的解析,必须是发生在@Configuration配置类被实例化后,因此它并不能提升优先级

  • static加在静态内部类上

1、 @Configuration(外层)配置类的初始化顺序依旧是按照AnnotationConfigApplicationContext的定义顺序来的; 对于内部类的@Configuration的初始化(不管是静态还是非静态),也依旧是外部的@Configuration完成后才行
2、 内部类里的@Bean的优先级均高于外层定义的@Bean,同时可以看到static静态内部类能够提升优先级,它比非静态内部类的优先级还高
3、内部类有限原则它只作用于本@Configuration类,也就是说仅在本主类内提升优先级。另外若出现多个内部类,按照定义顺序执行(static永远高于非static哦)
4、 内部类的访问权限无所谓,private都行。

4、bean加载顺序规则

直接上干货了,测试代码太长啦;

SpringBoot2.7以后自动装配的定义文件该成了org.springframework.boot.autoconfigure.AutoConfiguration.imports
在这里插入图片描述

  • Spring.factories中定义的自动装配类优先级最低
  • 本类中bean顺序按依赖优先+代码顺序原则,比如A/B/C三个Bean上中下顺序写的代码,A依赖了C,所以C比A和B都提前加载
  • 跨类的bean加载顺序按照依赖优先+bean名称字母顺序加载
  • 静态内部类bean与跨类bean加载顺序一致
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot自动装配原理可以分为以下几个关键步骤: 1. 启动过程:在Spring Boot应用启动时,会执行SpringApplication类的run方法。该方法会创建Spring应用上下文,并触发自动装配过程。 2. 自动装配过程:自动装配过程主要依赖于条件注解和自动配置类。 - 条件注解:Spring Boot提供了一系列条件注解,如@ConditionalOnClass、@ConditionalOnBean、@ConditionalOnProperty等。这些注解可以根据特定的条件来决定是否进行自动配置。 - 自动配置类:自动配置类使用@Configuration注解进行标识,通过@Bean注解来声明需要自动配置的Bean。自动配置类通常使用@Conditional注解来指定条件,只有当满足条件时才会生效。 3. 自动配置类的加载:Spring Boot会自动扫描项目中的META-INF/spring.factories文件,该文件中定义了需要自动配置的类。Spring Boot会根据这些类的条件进行加载和实例化。 4. Bean的创建:在自动配置类中使用@Bean注解声明的Bean会被Spring容器自动创建和管理。这些Bean的创建过程会经过Spring的各个处理器,如BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor等。 下面是一个简单的示例来说明Spring Boot自动装配的原理: ```java @Configuration @ConditionalOnClass(MyService.class) public class MyAutoConfiguration { @Bean public MyService myService() { return new MyService(); } } ``` 在上述示例中,@ConditionalOnClass注解表示只有当MyService类在类路径中存在时,该自动配置类才会生效。当应用启动时,Spring Boot会扫描到该自动配置类,并根据条件判断是否需要进行自动配置。如果满足条件,Spring Boot会实例化并管理MyService的Bean。 通过自动装配Spring Boot可以根据项目的实际需求,自动配置和管理各种Bean,从而减少了开发人员的配置工作,提高了开发效率。 请注意,上述示例只是简单示意,并不涵盖所有细节。实际的自动装配过程还涉及到条件判断、依赖关系处理、配置属性绑定等复杂的逻辑。如果你想深入了解Spring Boot自动装配原理,建议阅读Spring Boot的源码以及相关文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值