Spring容器以及Bean初始化流程图
面试中常问的:Bean的生命周期?
其实就是如图所示bean开始初始化的流程。
本文不会很深入的去查看源码,能力有限。但是易于帮助理解Spring的初始化流程以及Bean的生命周期。
ClassPathXmlApplicationContext
从一个大家很熟悉的方法开始
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Student student = context.getBean(Student.class);
System.out.println(student);
在执行new ClassPathXmlApplicationContext("bean.xml")
代码的时候,其内部执行了如下的构造方法
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// Set the config locations for this application context.
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
记住这个refresh
方法,spring容器的初始化全过程都集中的这个方面里面。
该文章基于xml配置文件的方式去创建bean以及演示,其实使用注解的方式也是差不多的。
refresh方法
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 创建BeanFacory之前的准备工作
prepareRefresh();
// 创建BeanFactory,加载bean definitions也是其内部执行的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 在BeanFactory使用之前做一些准备工作,对BeanFactory的一些属性进行初始化
prepareBeanFactory(beanFactory);
try {
// 如果我们自己实现了BeanFactoryPostProcessor中的postProcessBeanFactory方法,则执行(该方法本来就是一个空实现的方法,供我们去扩展)
postProcessBeanFactory(beanFactory);
// 实例化已注册的BeanFactoryPostProcessor对象(比如,spring内部实现的BeanFactoryPostProcessor对象),并且调用它们实现的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 以下四步都是在实例化bean之前做一些准备操作,它们不对bean做任何操作
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
// 实例化bean(这里特指了实例化所有非懒加载的bean)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
下面对一些重点方法进行分析。
obtainFreshBeanFactory
该方法中包括了创建BeanFactory、加载BeanDefinition等操作。
很好理解,在我们对bean进行正式的实例化、初始化操作时,首页你必须要一个IOC容器,也就是BeanFactory,其次,你必须要知道需要初始化的Bean的一些详细信息,这些详细信息就被封装在BeanDefinition中。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 创建BeanFactory
refreshBeanFactory();
// 返回BeanFactory
return getBeanFactory();
}
refreshBeanFactory:
protected final void refreshBeanFactory() throws BeansException {
// 如果当前存在BeanFactory,则销毁掉,表示我们要重新创建一个新的
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建BeanFactory方法,内部就是执行了new DefaultListableBeanFactory(getInternalParentBeanFactory())
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 加载bean definitions
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
loadBeanDefinitions:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为给定的BeanFactory对象创建一个BeanDefinitionReader对象
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
// 加载bean definitions
loadBeanDefinitions(beanDefinitionReader);
}
BeanDefinition:也就是我们定义的bean的一些信息,比如,bean的属性信息、class信息、name信息、是否是懒加载等。
从上面代码中可以看到,这里创建了一个XmlBeanDefinitionReader对象来加载bean definitions,不同的定义bean的方式会创建出不同的BeanDefinitionReader对象去读取bean definitions,这个也很好理解,比如我们可能不是用的xml的方式来配置定义bean的,而是使用properties配置文件,这个时候,你用XmlBeanDefinitionReader还能读取它里面定义的bean definition吗?
因此,BeanDefinitionReader提供了多种实现类:
XmlBeanDefinitionReader加载BeanDefinition的底层其实就是将xml文件解析成Document对象,然后读取这些标签信息,具体的细节并没有深入查看。
postProcessBeanFactory
点进去看一下,可以看到这个方式是个空方法
其实就是留给我们做一些扩展的,比如,你自己去实现了BeanFactoryPostProcessor中的postProcessBeanFactory
方法,那么在这里就会被调用
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("invoke MyBeanFactoryPostProcessor...");
}
}
invokeBeanFactoryPostProcessors
实例化已注册的BeanFactoryPostProcessor对象(比如,spring内部实现的BeanFactoryPostProcessor对象),并且调用它们实现的postProcessBeanFactory
方法,根据情况完成一些特点的功能,比如下面讲的替换配置文件中${}占位符就是在这里完成的。
finishBeanFactoryInitialization
该方法主要调用了preInstantiateSingletons
方法
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 通过beanName判断该bean是一个FactoryBean还是普通Bean,如果是FactoryBean则会进入这个if
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 如果是普通bean,则直接调用这个方法
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
其核心方法就是这个getBean
,实例化、初始化、循环依赖、注入属性等功能都是在这个方法里完成的,所以这个方法很重要。
该方法只调用了一个
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;
// 去三级缓存中分别查询对象 解析循环依赖的重要方法
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);
}
// ...
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 核心方法 创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// ...
}
该方法首先先去三级缓存中查询该对象是否存在,解决循环依赖的重要步骤之一,具体的可以看我的另一篇文章。
doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 通过反射的方式去创建出这个bean的实例,也就是实例化bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// ...
// 此处也是解决循环依赖的重要步骤之一
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 将实例化好的bean放入三级缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 以下都属于bean的初始化过程(bean的生命周期从这里开始),注意是初始化,实例化在上面已经完成了
Object exposedObject = bean;
try {
// 封装bean的一些属性,也就是调用set方法,在这一步之前,bean只是一个刚被实例化出来的空bean(啥属性都没封装)
populateBean(beanName, mbd, instanceWrapper);
// 初始化bean,调用PostProcessor以及init-method方法的过程,
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
createBeanInstance
通过反射的方式去实例化一个bean出来,其中又调用了instantiateBean
方法来完成的。
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
// 根据beanName以及它的BeanDefinition获取到对应的实例化策略,完成bean的实例化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
// ...
}
为了更清楚的看到,它是通过反射的方式创建的,这里就贴几个核心的代码
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
// 通过反射获取到当前class对象的构造器
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
}
}
// 刚刚获取到的构造器对象传入这个方法中
return BeanUtils.instantiateClass(constructorToUse);
}
}
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return KotlinDelegate.instantiateClass(ctor, args);
}
else {
Class<?>[] parameterTypes = ctor.getParameterTypes();
Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
Object[] argsWithDefaultValues = new Object[args.length];
for (int i = 0 ; i < args.length; i++) {
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
}
else {
argsWithDefaultValues[i] = args[i];
}
}
// 看这里
return ctor.newInstance(argsWithDefaultValues);
}
}
constructorToUse = clazz.getDeclaredConstructor();
ctor.newInstance(argsWithDefaultValues);
populateBean
这个方法主要是对刚刚实例化出来的bean对象进行属性的注入,注意,在没有执行这一步之前,实例化出来的bean只是一个空对象,也就是一个任何属性都没有被初始化的空对象!
大家可以去观察一下,执行完这一步,它的属性值就会被赋值上去了。
initializeBean
接下来就是这个方法了。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 当bean实现了Aware接口时,在这里会被调用对应的接口方法
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 调用我们实现的postProcessBeforeInitialization方法(BeanPostProcessor接口)
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用我们实现的postProcessAfterInitialization方法(BeanPostProcessor接口)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
注意:
applyBeanPostProcessorsBeforeInitialization
applyBeanPostProcessorsAfterInitialization
这两个方法的返回值都是被增强后的对象(代理对象)。
比如,我们在自己实现BeanPostProcessor接口这两个方法时,上述方法的返回值就是我们return的对象(被增强后的对象)。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("invoke postProcessBeforeInitialization defined by me");
Student student = (Student) bean;
student.setName("david");
return student;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("invoke postProcessAfterInitialization defined by me");
Student student = (Student) bean;
student.setAge(10);
return student;
}
}
Q: xml配置文件中的${} 占位符是如何替换为实际的值的?什么时候被替换的?
比如,我在bean.xml文件里面编写了如下的代码
<context:property-placeholder location="db.properties"></context:property-placeholder>
<bean id="student" class="com.pri.spring5.demo.Student">
<property name="name" value="${name}"></property> <!-- properties: name=rose -->
</bean>
Spring有很多内置的BeanFactoryPostProcessor的实现类,其中PropertySourcesPlaceholderConfigurer完成了这个功能
回想一下,在上述的spring初始化流程中,BeanPostFactory是在什么时候被调用的?
invokeBeanFactoryPostProcessors
。
验证:
首先我们在该方法上打一个断点,可以看到,在没有执行完该方法时,该bean的BeanDefinition中保存的属性信息依旧是一个未被替换值的占位符
该方法主要又调用了invokeBeanFactoryPostProcessors
方法
执行到这行代码,你会发现,确实有一个PropertySourcesPlaceholderConfigurer被找到了。
然后去调用invokeBeanFactoryPostProcessors
方法
很明显,该方法就是去调用我们实现的BeanFactoryPostProcessor的postProcessBeanFactory
方法,所以,这里postProcessBeanFactory所实现的postProcessBeanFactory
会被调用
进到它的postProcessBeanFactory
方法里,找到下面这行代码
这里就不去细看了,里面调用了doProcessProperties方法,也就是将我们BeanDefinition中的占位符都替换为实际的值得操作。
执行完这个方法,你就会发现,原本保存BeanDefinition中的占位符会替换为我们定义在properties文件中的实际值了