【Spring系列】Spring @DependsOn注解控制两个Bean的加载顺序

tech2022-10-18  108

目录

背景解决方案实现原理

背景

最近遇到了一个比较罕见的bug,灰度上线的机器在监控平台打的点应用名和方法名都是null,排查了一番,发现新增的A类调用了监控打点的切面B类的静态方法,而在Spring加载Bean的时候,先加载了A类的Bean,使得B类中需要Spring注入的被@Value修饰的应用名和方法名属性都没有注入成功。

A类

@Component public class A{ public void xxx(){ //用B类打点 B.registerInfo('A.xxx'); } }

B类

@Service('b') public class B{ private static String sAppName; private static String sMethodName; @Value("my_app") public void setAppName(String appName){ sAppName = appName; } @Value("my_method") public void setMethodName(String methodName){ sMethodName = methodName; } public static void registerInfo(String name){ //打点 } }

解决方案

注解方式注入的Bean 在A类上打上注解@DependsOn(‘b’),使得B类Bean优先于A类Bean在Spring中被加载

XML方式注入的Bean 在A类Bean对应xml节点加上depends-on=“b" 属性

<bean name="a" class="xxx.A" depends-on="b"/>

实现原理

在Spring Bean定义中有一个专门用于存储依赖Bean顺序的数组dependsOn,在加载Bean时会先去调用此Bean dependsOn数组中的Bean。

org.springframework.context.annotation.AnnotatedBeanDefinitionReader#registerBean

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); // 处理加在Bean上的注解 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations

// 取出加在Bean上的DependsOn注解的字符串数组存入Bean定义 if (metadata.isAnnotated(DependsOn.class.getName())) { abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value")); }

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

// 保证该Bean依赖的其他Bean先被初始化 // 取出Bean定义中的DependsOn数组 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); //先获取依赖的其他Bean getBean(dep); } }
最新回复(0)