上次我们说了Spring在解决循环引用时采用的三级缓存,以达成bean的提前曝光来解决循环引用问题。那么对于一个bean在Spring中是如何走过它平凡却又不平庸的一生的呢?来上一张借来的图片先看一看,在奶袋里有一个简略印象,然后听我扯一扯。
好的,还是从我们运行如下代码,获取一个user bean 开始我们的故事:
1 ClassPathResource resource = new ClassPathResource("bean.xml"); 2 DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); 3 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); 4 reader.loadBeanDefinitions(resource); 5 UserBean user = (UserBean) factory.getBean("user");
在启动spring第一次获取user bean 单例时,会触发spring的实例化进程。getBean()方法是实例化的入口方法,真正执行实例化进程的是AbstractAutowireCapableBeanFactory.createBean()中执行的doCreateBean()方法。
1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) 2 throws BeanCreationException { 3 4 // Instantiate the bean. 5 BeanWrapper instanceWrapper = null; 6 if (mbd.isSingleton()) { 7 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 8 } 9 if (instanceWrapper == null) { 10 instanceWrapper = createBeanInstance(beanName, mbd, args); //创建bean实例 11 } 12 final Object bean = instanceWrapper.getWrappedInstance(); 13 Class<?> beanType = instanceWrapper.getWrappedClass(); 14 if (beanType != NullBean.class) { 15 mbd.resolvedTargetType = beanType; 16 } 17 18 // Allow post-processors to modify the merged bean definition. 19 synchronized (mbd.postProcessingLock) { 20 if (!mbd.postProcessed) { 21 try { 22 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 23 } 24 catch (Throwable ex) { 25 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 26 "Post-processing of merged bean definition failed", ex); 27 } 28 mbd.postProcessed = true; 29 } 30 } 31 32 // Eagerly cache singletons to be able to resolve circular references 33 // even when triggered by lifecycle interfaces like BeanFactoryAware. 34 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && 35 isSingletonCurrentlyInCreation(beanName)); 36 if (earlySingletonExposure) { 37 if (logger.isTraceEnabled()) { 38 logger.trace("Eagerly caching bean '" + beanName + 39 "' to allow for resolving potential circular references"); 40 } 41 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 42 } 43 44 // Initialize the bean instance. 45 Object exposedObject = bean; 46 try { 47 populateBean(beanName, mbd, instanceWrapper); //填充bean实例,包括设置bean属性值(注入属性对象等) 48 exposedObject = initializeBean(beanName, exposedObject, mbd); //在此调用执行初始化bean 49 } 50 catch (Throwable ex) { 51 if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { 52 throw (BeanCreationException) ex; 53 } 54 else { 55 throw new BeanCreationException( 56 mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); 57 } 58 } 59 60 if (earlySingletonExposure) { 61 Object earlySingletonReference = getSingleton(beanName, false); 62 if (earlySingletonReference != null) { 63 if (exposedObject == bean) { 64 exposedObject = earlySingletonReference; 65 } 66 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { 67 String[] dependentBeans = getDependentBeans(beanName); 68 Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); 69 for (String dependentBean : dependentBeans) { 70 if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { 71 actualDependentBeans.add(dependentBean); 72 } 73 } 74 if (!actualDependentBeans.isEmpty()) { 75 throw new BeanCurrentlyInCreationException(beanName, 76 "Bean with name '" + beanName + "' has been injected into other beans [" + 77 StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + 78 "] in its raw version as part of a circular reference, but has eventually been " + 79 "wrapped. This means that said other beans do not use the final version of the " + 80 "bean. This is often the result of over-eager type matching - consider using " + 81 "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); 82 } 83 } 84 } 85 } 86 87 // Register bean as disposable. 88 try { 89 registerDisposableBeanIfNecessary(beanName, bean, mbd); //注册执行销毁的DisposableBean如果需要的话 90 } 91 catch (BeanDefinitionValidationException ex) { 92 throw new BeanCreationException( 93 mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); 94 } 95 96 return exposedObject; 97 }
通过追踪上面doCreateBean()方法,我可以看到在bean实例化完成后调用populateBean()来对实例化后的user 对象(bean)进行填充,其主要是完成了user属性的设置。而后执行initializeBean()来完成对实例化后的bean完成后续的初始化工作。看下面代码:
1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { 2 if (System.getSecurityManager() != null) { 3 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { 4 invokeAwareMethods(beanName, bean); 5 return null; 6 }, getAccessControlContext()); 7 } 8 else { 9 invokeAwareMethods(beanName, bean); //检查执行、激活aware 10 } 11 12 Object wrappedBean = bean; 13 if (mbd == null || !mbd.isSynthetic()) { 14 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //执行BeanPostProcesser增强的前置处理 15 } 16 17 try { 18 invokeInitMethods(beanName, wrappedBean, mbd); 19 } 20 catch (Throwable ex) { 21 throw new BeanCreationException( 22 (mbd != null ? mbd.getResourceDescription() : null), 23 beanName, "Invocation of init method failed", ex); 24 } 25 if (mbd == null || !mbd.isSynthetic()) { 26 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); //执行BeanPostProcesser增强的后置处理 27 } 28 29 return wrappedBean; 30 }
我在上面的initializeBean()方法中看到,在对bean进行初始化之前首先调用下面invokeAwareMethods()方法,通过一系列的判断来检查当前的user bean是否实现了一系列的aware接口,并激活其实现的方法。这一阶段主要感知的是BeanNameAware、BeanClassLoaderAware、BeanFactoryAware :
- BeanNameAware:对该 bean 对象定义的 beanName 设置到当前对象实例中
- BeanClassLoaderAware:将当前 bean 对象相应的 ClassLoader 注入到当前对象实例中
- BeanFactoryAware:BeanFactory 容器会将自身注入到当前对象实例中,这样当前对象就会拥有一个 BeanFactory 容器的引用。
1 private void invokeAwareMethods(final String beanName, final Object bean) { 2 if (bean instanceof Aware) { 3 if (bean instanceof BeanNameAware) { 4 ((BeanNameAware) bean).setBeanName(beanName); 5 } 6 if (bean instanceof BeanClassLoaderAware) { 7 ClassLoader bcl = getBeanClassLoader(); 8 if (bcl != null) { 9 ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); 10 } 11 } 12 if (bean instanceof BeanFactoryAware) { 13 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); 14 } 15 } 16 }
而后,是执行BeanPostProcesser对bean的增强。在BeanPostProcesser前后置增强方法之间执行的是下面初始化方法,看源码注释。以我英语三级60分的半瓶子水给大家解释一下就是:给传进来的这个bean一个机会响应现在它所有的属性都被设置完成了,和另一个去感知自己拥有的bean factory 的机会。这个意思就是我要检查一下它是不是实现了InitializingBean接口或者自定义了init method,如果需要我就执行一下子。总结来说就两点,一是检查user是不是实现了InitializingBean这个接口,这个接口中有一个afterPropertiesSet()方法,实现了就执行一下这个方法完成一些初始化工作。再就是检查一下,用户是不是配置了自定义的init-method方法,配置了就通过反射的方式调用一下完成用户自定义的初始化。
1 /** 2 * Give a bean a chance to react now all its properties are set, 3 * and a chance to know about its owning bean factory (this object). 4 * This means checking whether the bean implements InitializingBean or defines 5 * a custom init method, and invoking the necessary callback(s) if it does. 6 * @param beanName the bean name in the factory (for debugging purposes) 7 * @param bean the new bean instance we may need to initialize 8 * @param mbd the merged bean definition that the bean was created with 9 * (can also be {@code null}, if given an existing bean instance) 10 * @throws Throwable if thrown by init methods or by the invocation process 11 * @see #invokeCustomInitMethod 12 */ 13 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) 14 throws Throwable { 15 16 boolean isInitializingBean = (bean instanceof InitializingBean); //是否实现了InitializingBean 17 if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { 18 if (logger.isTraceEnabled()) { 19 logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); 20 } 21 if (System.getSecurityManager() != null) { 22 try { 23 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { 24 ((InitializingBean) bean).afterPropertiesSet(); 25 return null; 26 }, getAccessControlContext()); 27 } 28 catch (PrivilegedActionException pae) { 29 throw pae.getException(); 30 } 31 } 32 else { 33 ((InitializingBean) bean).afterPropertiesSet(); 34 } 35 } 36 37 if (mbd != null && bean.getClass() != NullBean.class) { 38 String initMethodName = mbd.getInitMethodName(); 39 if (StringUtils.hasLength(initMethodName) && 40 !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && 41 !mbd.isExternallyManagedInitMethod(initMethodName)) { //有没有自定义 init method 42 invokeCustomInitMethod(beanName, bean, mbd); 43 } 44 } 45 }
到此你要的bean就准备好了,你可以用它来做你想让它干的事儿了。做完你给它的作业,并不会立即调用销毁的方法,因为这时候spring容器还在运行,只有当spring容器关闭的时候才会执行。但是销毁的方法,spring不会自动去调用,需要我们来手动做一些操作去通知spring容器调用这些方法。对于BeanFactory容器,我们可以通过主动调用destorySingletons()通知 BeanFactory 容器去执行相应的销毁方法。如果是ApplicationContext 容器则调用registerShutdownHook() 方法.
所要执行的销毁方法和InitializingBean 和 init-method 用于对象的自定义初始化工作是类似的。首先判断是否实现了DisposableBean接口,然后是否配置了destroy-method方法来自定义销毁工作。
最后,我们看一下BeanFactory容器是如何执行destorySingletons()方法的,代码如下:
1 public void destroySingletons() { 2 if (logger.isTraceEnabled()) { 3 logger.trace("Destroying singletons in " + this); 4 } 5 synchronized (this.singletonObjects) { 6 this.singletonsCurrentlyInDestruction = true; 7 } 8 9 String[] disposableBeanNames; 10 synchronized (this.disposableBeans) { 11 disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet()); //获取所有注册了DisposableBeans的beanName 12 } 13 for (int i = disposableBeanNames.length - 1; i >= 0; i--) { //遍历执行 14 destroySingleton(disposableBeanNames[i]); 15 } 16 17 this.containedBeanMap.clear(); 18 this.dependentBeanMap.clear(); 19 this.dependenciesForBeanMap.clear(); 20 21 clearSingletonCache(); 22 }