Spring 初始化过程中GetBean方法分析
经过前面的铺垫我们终于来到了IOC容器初始化最核心的部分(我个人认为)。在getBean时会调用AbstractBeanFactory#doGetBean()方法来获取单例Bean,在doGetBean中会先做一个缓存检查,判断是否之前手动插入到ioc,若存在缓存会根据缓存来拿Bean,暂不分析。
随后会判断当前Bean是否存在依赖,存在依赖时会先实例化依赖的Bean,此处暂不讨论,后续单独讨论。
不存在依赖的情况下,调用父类DefaultSingletonBeanRegistry#getSingleton方法,并且传入一个单例工厂,通过AbstractAutowireCapableBeanFactory#createBean方法来创建Bean,这个方法的注解中说明这是此类的核心方法,用来创建、填充Bean,并且调用BeanPostProcessor。关键代码如下所示
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 此处根据beanName将class load到jvm,并且给mbd的instanceclass字段赋值
Class> resolvedClass = resolveBeanClass(mbd, beanName);
...........................................................
// 此处真正创建对象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
Spring中不管前面如何铺垫,最终执行操作的方法均为doXXX,所以,看到这个关键字我们就应该知道我们马上要解开面纱了。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
// 实例化一个空对象出来
instanceWrapper = createBeanInstance(beanName, mbd, args);
// 给对象的属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 调用各种回调
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
上面只列出了doCreateBean中我认为最关键的三个方法,下面我们注意分析这三个方法。
首先我们来看实例化对象核心代码
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
/**
* Instantiate the given bean using its default constructor.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return a BeanWrapper for the new instance
*/
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
// 通过实例化策略来实例化对象,默认策略是cglib,但是不存在Override方法的对象调用的实例化方法在父类SimpleInstantiationStrategy中
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
在SimpleInstantiationStrategy#instantiate方法没什么特别的,基本就是通过bd获取class,再获取constructor,之后通过反射创建对象后返回。
其次我们来关注给对象的属性赋值
此方法会处理AutoWired注解的注入逻辑,实现依赖注入。具体核心代码如下
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
如上所示,ioc容器会遍历已有的BeanPostProcessor,在遍历到AutoWiredAnnotationBeanPostProcessor(第一章介绍入口时registerBeanPostProcessors方法中提到了)时会实现自动装配。
可以参考AutoWiredAnnotationBeanPostProcessor类的官方注解
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
* that autowires annotated fields, setter methods and arbitrary config methods.
* Such members to be injected are detected through a Java 5 annotation: by default,
* Spring's {@link Autowired @Autowired} and {@link Value @Value} annotations.
*
* Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
* if available, as a direct alternative to Spring's own {@code @Autowired}.
*/
从官方注解中可以看到,这个后置处理器的功能是为标有Spring的@AutoWired、@Value注解和JSR-330的@Injected的注解的属性赋值。另外其他的BeanPostProcessor也各有功能,后面有机会的话单独分析。我们先来关注自动装配模块。
通过跟源码我们发现,实际上的处理过程在DefaultListableBeanFactory#doResolveDependency()方法中,关键代码如下
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
/**
* Find bean instances that match the required type.
* Called during autowiring for the specified bean.
* @param beanName the name of the bean that is about to be wired
* @param requiredType the actual type of bean to look for
* (may be an array component type or collection element type)
* @param descriptor the descriptor of the dependency to resolve
* @return a Map of candidate names and candidate instances that match
* the required type (never {@code null})
* @throws BeansException in case of errors
* @see #autowireByType
* @see #autowireConstructor
*/
protected Map findAutowireCandidates(
@Nullable String beanName, Class> requiredType, DependencyDescriptor descriptor) {
// 从ioc容器中根据bean类型来加载所有的单例(包括祖先类实例)
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
// 这个方法里面会调用getBean方法从容器中获取待注入的对象
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
return result;
}
通过上述代码会获取到需要注入的对象,后面要做的就是通过反射,将值赋给需要注入的字段。
需要注意的是,在跟踪源码的过程中发现@Autowired和@Inject注解其实都是按类型注入,而@Resource则是按名称注入,@Autowired注解是Spring实现的注解,如果需要注入的Bean不是单例而存在多个,比如说多数据源,此时需要配套@Qualified注解来使用。而@Inject是JSR-330标准的注解,在类似多数据源的情况下需要使用@Named来确定。另外,@Autowired注解支持required属性,如果该属性为false,则在容器中不存在对应类型时会注入为空,而@Inject注解不存在这个特性,除此之外@Auto wired和@Inject完全没区别
最后我们来关注调用回调
从方法注解上我们可以看到,在该阶段主要是负责调用工厂的各类回调(主要是BeanNameAware、BeanClassLoaderAware以及BeanFactoryAware),同时调用init方法(Spring在XML或@Bean的方式声明一个Bean时可以指定InitMethod和DestoryMethod)以及Bean的后置处理器(主要是BeanPostProcessor中的postProcessBeforeInitialization和postProcessAfterInitialization方法),下面我们通过代码来分析。
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 调用工厂的回调
invokeAwareMethods(beanName, bean);
// 调用后置处理器的beforeInitialization
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 调用InitializingBean#afterPropertiesSet或initMethod
invokeInitMethods(beanName, wrappedBean, mbd);
// 调用后置处理器的afterInitialization
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
在applyBeanPostProcessorsBeforeInitialization方法中会调用ApplicationContext级别的相关回调,包括EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware
在Spring MVC中会通过invokeInitMethods方法来调用InitializingBean#afterPropertiesSet方法实例化RequestMappingHandlerMapping等信息。后面在分析Spring MVC源码时在单独分析。
而applyBeanPostProcessorsAfterInitialization方法大多都是直接返回bean,Spring保留了用户扩展的需求。
至此Spring容器的getBean就已经介绍完了。结束这一步基本上Spring容器的启动过程也就快结束了。通过分析我们了解了很多Spring的原理,更重要的是开始慢慢了解Spring的设计思想,相信这些思想能让我们更好的编码,写出更好、更优雅的code。