初始化bean(一)—— 首次加载
上一篇博客,讲了下spring如何解析xml,并将我们的配置转换成BeanDefinition,最终注册到BeanDefinitionRegistry中(默认实现,DefaultListableBeanFactory)接下来就要说明,spring拿到这个BeanDefinition后,如何将其初始化。由于内容比较多,会分几次来说明。
从一个入口开始
public class TestDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("person");
System.out.println("person name:" + person.getName());
}
}
回到第一篇博客,讲spring如何加载配置文件的地方开始spring资源文件的加载
使用spring获取bean的入口,就在context.getBean()
上
@Override
public Object getBean(String name) throws BeansException {
//断言spring是否已初始化,并且未关闭
assertBeanFactoryActive();
//这里的beanFactory默认是DefaultListableBeanFactory
return getBeanFactory().getBean(name);
}
ClassPathApplicationContext
将获取bean的方法,委托给了DefaultListableBeanFactory
获取bean流程
由于bean的加载及获取流程很长,本次分析,只考虑第一次加载的情况
。去掉这些缓存及些异常处理,日志的代码,然后也只分析 singleton
的情况,整个流程大概这样。
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//1、转换beanName
final String beanName = transformedBeanName(name);
Object bean;
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 有缓存 ...
} else {
// ...
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 父 factory 里加载
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//2、转换成RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//依赖,先不考虑
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
//...
}
// Create bean instance.
if (mbd.isSingleton()) {
//3、关键:单例类的初始化
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
//prototype ...
}
else {
// 其他scope ...
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
// 如果类型不一致,做类型转换
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
return (T) bean;
}
1、转换beanName
// 1、对于factoryBean &bean -> bean
// 2、对于别名,将其转换成真实的名字
final String beanName = transformedBeanName(name);
这一步主要是将FactoryBean的前缀替换掉,比如context.getBean("&factoryBean")
,beanName会去掉前缀,被替换成factoryBean
,关于FactoryBean和BeanFactory的区别,这里就不介绍了。
2、转换成RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//如果要初始化的是一个抽象类,就抛异常
checkMergedBeanDefinition(mbd, beanName, args);
之前分析BeanDefinition时候,我们知道了注册的BeanDefinition实现类是GenericBeanDefinition。但是获取Bean的步骤中,使用的都是RootBeanDefinition,所以这里做了一次GenericBeanDefinition到RootBeanDefinition的转换。
3、单例类的初始化
随后,我们最后要分析的就是,最关键的一步,单例对象的初始化。
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
这里,调用了getSingleton方法。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory);
这里先记着,调用getSingleton时候传了两个参数:
1)beanName
2)一个ObjectFactory的匿名内部类,getObject的实现是直接调用createBean方法
随后我们继续看getSingleton方法。同样,这里也会去掉很多干扰的代码(比如日志、异常处理)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
//先试着从缓存中加载
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while the singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//调用ObjectFactory的getObject生成这个对象
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
//添加到缓存里
addSingleton(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
如果忽略掉所有的异常处理逻辑,这个方法其实就做了三件事。
1)试着从缓存里获取这个对象(缓存就是个map)
2)回调objectFactory的getObject方法创建这个对象(模板方法模式)
3)存到缓存里
3.1 bean真正创建的地方createBean方法
默认实现是在AbstractAutowireCapableBeanFactory里。这个方法很长,也做了很多的回调。这里只分析最重要的一部分,初始化。跟到最后,源码是在InstantiationStrategy
里。
同样默认实现在SimpleInstantiationStrategy里
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
//反射调用 Constructor.newInstance方法
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
这里的实现,就是简单的通过反射调用 Constructor.newInstance 来初始化对象。
3.2 回到getObjectForBeanInstance方法
已经跟到createBean这一步了,我们回头看看获取到这个对象后,spring又做了什么。
// 省略匿名内部类
sharedInstance = getSingleton(beanName, ...);
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
下一步就是调用getObjectForBeanInstance
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 以 & 开头,但是创建的对象不是 FactoryBean就抛异常
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// 不是FactoryBean 或者 要获取的就是FactoryBean (以&开头的name)
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
//获取FactoryBean生成的bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
这一步,涉及到FactoryBean和BeanFactory的区别。这里只说明如下几点。
1)如果一个bean的class 配置了实现FactoryBean接口的类,比如
<bean id="person" class="com.hdj.PersonFactoryBean"/>
那么,通过context.getBean("person")
获取到的就不是PersonFactoryBean而是PersonFactoryBean.getObject返回的对象。
2)如果想要获取PersonFactoryBean对象,就需要这样调用context.getBean("&person")
说明了这两点,这里就挺容易理解的了。
1)不是FactoryBean 或者 要获取的就是FactoryBean (以&开头的name) 直接返回createBean创造的对象即可
2)是FactoryBean 并且要获取的是getObject 对象,需要返回 FactoryBean.getObject 对象。
此外,这里省略了getObjectFromFactoryBean的细节,因为涉及了很多缓存。这些缓存的关系,下面几篇博客会分析。
总结
绕了很半天,终于得以发现spring的初始化逻辑的很小一部分。
1)获取beanName对应的Class类。
2)通过反射方式,初始化它。
3)如果是FactoryBean 还要返回getObject 对象
4)缓存最后的结果
当然这里的分析省略了很多,比如:
1)构造函数的选择,如果一个对象有多个构造函数,那么如何选择构造函数
2)依赖注入如何实现
3)各种PostProcessor
这些内容都会在后续博客里一点点说明
思考
学习spring时候,都会学到有一步骤,beanFactory.getBean("person")
通过这一行代码,一步步跟踪代码,我们很自然地会知道spring的入口在哪,spring是如何帮我们初始化bean的,又是如何实现依赖注入、aop等一系列强大的功能。
但是,现在开发大多是web工程,对于一个web工程,spring的入口又在哪里?甚至对于springboot来说,连xml都没了,spring的入口又在哪里?
spring为我们简化了开发的很多步骤,阅读源码又是个挺困难过程。希望能坚持下去,一一弄清楚一系列平常开发所接触不到的问题。