Spring版本
5.2.5.RELEASE
参考
《芋道源码》
源码解读
1. AbstractAutowireCapableBeanFactory#initializeBean
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction
主流程主要包含四个步骤:
-
invokeAwareMethods
进行一些属性的设置 -
applyBeanPostProcessorsBeforeInitialization
应用BeanPostProcessors
的applyBeanPostProcessorsBeforeInitialization
方法 -
invokeInitMethods
应用初始化方法 -
applyBeanPostProcessorsAfterInitialization
应用BeanPostProcessors
的applyBeanPostProcessorsAfterInitialization
2. AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((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);
}
}
}
Aware
接口是spring提供的一种回调机制,这里简单地设置了beanName
、beanClassLoader
、beanFactory
的属性,关于Aware
接口可戳// TODO
3. AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 应用每个PostProcessors
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
获取到BeanPostProcessor集合,遍历,应用每个BeanPostProcessor
的postProcessBeforeInitialization
方法,如果返回值为空,则返回上一次处理后的bean
4. AbstractAutowireCapableBeanFactory#invokeInitMethods
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
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
做了俩件事:
- 首先判断bean是否是
InitializingBean
类型,如果是,应用afterPropertiesSet
方法,从方法名可以看出,该方法提供了一个在设置完毕property之后再去修改property的机会 - 应用自定义的
init-method
方法
4.1 InitializingBean
public interface InitializingBean {
/**
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
* This method allows the bean instance to perform validation of its overall
* configuration and final initialization when all bean properties have been set.
* @throws Exception in the event of misconfiguration (such as failure to set an
* essential property) or if initialization fails for any other reason
*/
void afterPropertiesSet() throws Exception;
}
InitializingBean
接口仅包含afterPropertiesSet
一个方法,下面通过一个小demo来展示其效果
4.1.1 demo
4.1.1.1 Teacher.java
public class Teacher implements InitializingBean {
private String name;
@Override
public void afterPropertiesSet() throws Exception {
name = "name set by afterPropertiesSet";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4.1.1.2 spring.xml
4.1.1.3 测试
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Teacher teacher = (Teacher) context.getBean("teacher");
System.out.println(teacher.getName());
}
}
4.1.1.4 结果
4.1.2 结论
可以看到,在spring.xml中,name属性设置的name set by property label
已经被afterPropertiesSet
方法中的name set by afterPropertiesSet
所覆盖
4.2 init-method
对4.1中的demo稍加修改
4.2.1 demo
4.2.1.1 Teacher.java
public class Teacher implements InitializingBean {
private String name;
@Override
public void afterPropertiesSet() throws Exception {
name = "name set by afterPropertiesSet";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void initMethod() {
this.name = "name set by init method";
}
}
4.2.1.2 spring.xml
4.2.1.3 结果
4.2.2 源码解析
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
// 如果init-method设置为afterPropertiesSet,那么前面已经运行过了,没必要再跑一遍
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 通过反射调用自定义初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
这里做了一个优化,如果init-method
设置为afterPropertiesSet
方法,那么其实4.1中已经应用了init-method
,就无需再次运行了,而invokeCustomInitMethod
方法的核心在于使用反射来应用init-method
方法:
ReflectionUtils.makeAccessible(methodToInvoke);
methodToInvoke.invoke(bean);
5. AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
@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;
}
逻辑与第三点大同小异
总结
初始化bean整体逻辑相对于其他流程来说,可以说是简单了很多,通过俩个小demo,也更清晰地理解了源码的执行流程,没有什么比实例来得更有说服力了。