Spring之@DependsOn的实现原理

为什么要控制Bean的加载顺序?
首先spring容器对一般的bean的初始化顺序是不确定的(个别Spring自身初始化用的bean和配置类的bean会优先初始化),但是我们在某些场景下(具体场景如下面举例),我们又需要控制顺序。这时候,就用到了@DenpendsOn。

一、@DependsOn的使用

使用场景:

1、beanA 间接依赖 beanB并不是直接通过 构造方法或@Autowired等方式注入。如果beanA有一个属性,需要在初始化的时候对其进行赋值(需要在初始化的时候做,是因为这个属性其实是包装了其它的几个Bean的,比如说代理了BeanB,所以这就形成了BeanA间接的依赖BeanB。

2、beanA是事件发布者(或JMS发布者),beanB(或其他监听器)负责监听这些事件,典型的如观察者模式。我们不想监听器beanB错过任何事件,那么B需要首先被初始化。

代码示例:

@ComponentScan("com")
public class AppConfig {
}
@Component
public class EventA {
    public EventA() {
        System.out.println("EventA:初始化");
    }
}
@Component
public class EventB {
    public EventB() {
        System.out.println("EventB:初始化");
    }
}
public class DependsOnTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

运行结果:

AMonitor:初始化
EventA:初始化
EventB:初始化

按照上面的运行结果来看,监听器初始化时候,事件A和事件B还没有加载完成。这样就会导致我们错过事件,这在开发中是绝对不允许的。那怎么办?这时候就需要我们的**@DependsOn**注解了。

我们在我们的AMonitor监听器上加上注解,其他代码不变,代码如下。

@Component
@DependsOn({"eventA","eventB"})
public class AMonitor {
    public AMonitor() {
        System.out.println("AMonitor:初始化");
    }
}

再次查看运行结果:

EventA:初始化
EventB:初始化
AMonitor:初始化

运行结果,如我们预期。简单的使用就介绍到这里。

二、@DenpendsOn原理介绍

我们都知道在使用一个bean之前,肯定会去创建一个bean。spring中常见的套路就是,每次都是先判断当前这个组件有没有,没有就去创建,有就直接拿来用,包括第一次使用也是。


照这样说的话,那么我们在使用AMonitor监听器这个bean之前,肯定先去判断有没有,因为我们是初始化,肯定是没有的,所以去创建。


在spring容器初始化过程中,使用到bean 首先要去,getBean(非关键代码直接省略,有兴趣的可以打断点看调用栈)。
然后调用AbstractBeanFactory类中的doGetBean()方法

doGetBean()代码如下:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		// 先去单例池中判断,有没有当前这个bean。
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		//如果单例池中没有这个bean往下走
		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// 从合并后的beandefinition中,拿到@DepensOn注解内容,和注解的值一样是个数组。
				String[] dependsOn = mbd.getDependsOn();
				//判断dependsOn这个数组是否为空
				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 + "'");
						}
						
						//这个dependentBeanMap是在将一个.class编程beandefinition时,获取注解@DependsOn注解的内容,然后填入的。为的就是以后创建bean的时候使用。
						//如果判断都通过,再进入这个方法,验证dependentBeanMap中是否有被依赖的bean。
						registerDependentBean(dep, beanName);
						try {
						   //验证通过,直接去getBean(),然后循环以上步骤,调用doGetBean,然后调用createBean先把被依赖的bean创建出来(EventA,EventB),再往下走,继续创建当前bean的过程(AMonitor)。
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// Check if required type matches the type of the actual bean instance.
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

registerDependentBean()方法:

public void registerDependentBean(String beanName, String dependentBeanName) {
		String canonicalName = canonicalName(beanName);
		/**
		这个dependentBeanMap是在将一个.class编程beandefinition时,
		获取注解@DependsOn注解的内容,然后填入的。为的就是以后创建bean的时候使用。
		**/
		synchronized (this.dependentBeanMap) {
			Set<String> dependentBeans =
					this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
			//然后把dependentBeanName=AMonitor,添加到dependentBeans。
			//作为缓存,后续使用的时候直接拿。
			if (!dependentBeans.add(dependentBeanName)) {
				return;
			}
		}

		synchronized (this.dependenciesForBeanMap) {
			Set<String> dependenciesForBean =
					this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
			dependenciesForBean.add(canonicalName);
		}
	}

三、总结

其实我们通过看源码以后,可以大体认为@DependsOn实际上就是通过,提前做判断,然后提前去创建了被依赖的bean。当然,真正源码中的处理,还要考虑到很多情况,例如bean是否是单例,bean是否是FactoryBean等等,而且你要真正的理解源码,还要去搞懂spring在这之前做了什么,这是一个漫长的学习过程。博文中只是做了简单的介绍,还有很多不足的地方,欢迎大家的友善建议,如果有对spring有深厚的兴趣,也可以加入Java技术交流群:805069260,欢迎大家。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章