那我们直接接着上一章createBean方法来讲解了
今天主要讲bean的创建过程,在createBean中的方法,创建一个bean的时候,基本的流程如下图。
从加载类开始就是我们创建bean的流程,至于启动ApplicationContext、初始化BeanFactory、扫描等源码,小编会在后续文章中编写。
那么今天的内容是整体来认识创建一个bean的基本流程,根据源码、案例进行讲解。但是一些复杂的源码小编需要留到后面文章讲解,比如推断构造方法、属性填充本章内容不会具体讲解!!!
首先在创建bean之后,需要通过bd来获取class,有了class才能真正进行实例化操作,加载类这边就不详细的讲解了。
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 获取类信息
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
// 对通过XML定义的bean中的look-up方法进行预处理
// 对于@Lookup注解标注的方法不在这里进行处理,@AutowiredAnnotationBeanPostProcessor会处理@Lookup注解
// 不是本章重点,就不深究了
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 1、实例化前
Object bean = resolveBeforeInstantiation(beanName, mbdToUse); // 对象
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 创建bean Spring自带的创建bean的方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
先来说说,实例化前是个什么操作,实现InstantiationAwareBeanPostProcessor接口,重写postProcessBeforeInstantiation方法,在每一个bean创建之前都会经过实例化前的方法。可能有小伙伴就会想,这个步骤有什么用作?使用场景是什么样子的。 这个方法可以影响创建bean的后续流程,如果这个方法返回的不是null,那么后续流程就都不会执行了,直接返回这个方法返回的对象。
看代码执行结果,这里返回多个实例化前是因为,有多个bean,每创建一个bean就会输出一次。 在实例化前方法中判断了如果是userService,则直接返回User对象,最后结果控制台输出的也是User对象。
其实spring就是提供了这么一个功能点,可以选择用或者不用,但是这确实是属于创建一个bean的步骤之一。
@Component
public class KkBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("实例化前");
if (beanName.equals("userService")) {
return new User();
}
return null;
}
}
测试类-----------
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// getBean方法,获取一个bean,如果没有则会去创建
System.out.println(applicationContext.getBean("userService"));
}
输出结果-----------
实例化前
实例化前
实例化前
实例化前
com.kk.entity.User@240237d2
实例化前源码也是很简单,获取到所有实现了InstantiationAwareBeanPostProcessor接口的类,然后遍历调用方法。
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// beforeInstantiationResolved为null或true
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 实例化前
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
// 获取所有的BeanPostProcessors
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 类型判断
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 调用实例化前的方法
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
讲解完实例化前就只剩下这个方法了,doCreateBean,这个方法源码比较长,小编分几个段落贴出代码讲解。小编这里只贴出来比较关键部分的代码进行讲解,其他和流程无关的代码就不讲解了。
实例化前然后就是实例化对象了,但是在这个实例化的方法中,还有一个很重要的一步就是推断构造方法,因为先要确定好了用哪个构造方法,才能去实例化对象。
目前小伙伴只需要了解这个方法能够返回一个对象就行,至于推断构造方法后续文章在讲解。
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// factoryBeanObjectCache:存的是beanName对应的FactoryBean.getObject()所返回的对象
// factoryBeanInstanceCache:存的是beanName对应的FactoryBean实例对象
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 2、实例化
if (instanceWrapper == null) {
// 创建bean实例 = new USerSerive()
// 这个方法等到讲解spring推断构造方法仔细讲解
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
然后接着往下翻代码,在实例化之后,还有一个步骤就是实例化后,相关源码如下populateBean方法中。
// Initialize the bean instance.
// 对象已经暴露出去了
Object exposedObject = bean;
try {
// 3、实例化后、填充属性
populateBean(beanName, mbd, instanceWrapper);
// 4、 初始化 和 BeanPostProcessor 正常AOP
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);
}
}
在populateBean中,如下代码就是实例化后的源码,还是只需要实现InstantiationAwareBeanPostProcessor接口,重写postProcessAfterInstantiation方法,即可。
实例化后的逻辑和实例化前都是一样的,每创建一个bean都会执行实例化后的方法。 populateBean还剩下属性填充的代码就不讲解了,这个和依赖注入相关,后续文章讲解。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 实例化后
// 可以提供InstantiationAwareBeanPostProcessor,控制对象的属性注入
// 我们可以自己写一个InstantiationAwareBeanPostProcessor,然后重写postProcessAfterInstantiation方法返回false,那么则不会进行属性填充了
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// 省略了自动注入的代码,后续文章讲解
}
@Component
public class KkBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("实例化前");
if (beanName.equals("userService")) {
return new User();
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("实例化后");
return false;
}
}
那最后只剩下initializeBean这个方法了,这个方法基本上包含了三块内容。 执行Aware,初始化前、初始化、初始化后。
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 {
// 4.1、执行Aware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 4.2、初始化前
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 4.3、初始化
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()) {
// 4.4、初始化后 AOP ()
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
先来讲解一下Aware,这其实是spring提供一种回调机制,就是一个bean实例完之后,我们可以对这个bean做一些其他事情。 比如,一个bean想获取到自己的beanName属性,这个时候Aware就能够实现。
@Component
public class UserAware implements BeanNameAware {
public String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// getBean方法,获取一个bean,如果没有则会去创建
UserAware userAware = (UserAware) applicationContext.getBean("userAware");
System.out.println(userAware.beanName);
}
userAware
那么这个功能是怎么实现的呢? 我们来看具体的源码,单独看待这个方法,感觉spring的源码也不怎么难的样子。当然这里小编只演示了一种Aware类型,还有其他几种小编就不一一演示啦。
/**
* 执行Aware
*
* @param beanName
* @param bean
*/
private void invokeAwareMethods(final String beanName, final Object bean) {
// 对bean进行类型判断
if (bean instanceof Aware) {
// 这个就是我们刚刚演示对Aware类型
if (bean instanceof BeanNameAware) {
// 调用了setBeanName方法,从而进行赋值操作
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
接下来初始化前、后小编一起讲了。整体的逻辑实例化前、后差不多。实现BeanPostProcessor接口,我们也称之为bean的后置处理器。postProcessBeforeInitialization 初始化前的方法、postProcessAfterInitialization 初始化后的方法。
@Component
public class KkBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前");
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后");
return null;
}
}
源码如下:
/**
* 初始化前
*
* @return
* @throws BeansException
*/
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
/**
* 初始化后
*
* @return
* @throws BeansException
*/
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
最后就是初始化的方法了,在初始化前的下一步就是真正的进行初始化了。
@Component
public class KkInitializingBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化");
}
}
源码如下:
/**
* bean的初始化
*/
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 判断bean是否实现InitializingBean接口
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
// 安全管理不用管
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
// 调用初始化的方法
((InitializingBean) bean).afterPropertiesSet();
}
}
// 这段代码的逻辑是,如果在bd中设置了initMethodName属性,也就是对应的初始化的方法
// 如果设置了,那么就会执行该方法
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 真正的执行
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
感觉这篇文章写的有点乱乱的,主要是这个源码通过文章来解释,有些地方确实不好明白,但是对于这个spring创建bean的流程来说,不算太难,但是要认真反复多看两遍。
最后的总结的流程,其实和图片上类似,但是还有一个BeanDefinition的后置处理没有讲解。小编在结尾说一下吧,还记得初始化bean,最后一步可以根据mbd.getInitMethodName() 来获取一个初始化的方法吗?
那么这个InitMethodName怎么进行设置呢? 就可以通过BeanDefinition的后置处理来进行设置,实现MergedBeanDefinitionPostProcessor接口,然后就可以进行设置啦。
对应的源码位置在:doCreateBean方法中,在实例化后,接着就是调用BeanDefinition后置处理的代码了,道理和实例化前后、初始化前后的逻辑一样,只是判断bean类型不一样而已,具体参考源码吧~~
@Component
public class KkDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 针对某一个bean进行设置
if (beanName.equals("userAware")) {
beanDefinition.setInitMethodName("init");
}
}
}
// beanDefinition 后置处理
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 运行修改合并好了的BeanDefinition
// 这里会查找@Autowired的注入点(InjectedElement),并把这些注入点添加到mbd的属性externallyManagedConfigMembers中
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
接下来的文章就会对Spring是如何进行扫描、如何实现推断构造方法、属性填充,以及spring启动源码进行一一分析,看源码就是要这样,一个一个功能进行看,细水长流 ~~~~~~