初始化bean(一)—— 首次加载

简介: 上一篇博客,讲了下spring如何解析xml,并将我们的配置转换成BeanDefinition,最终注册到BeanDefinitionRegistry中(默认实现,DefaultListableBeanFactory)接下来就要说明,spring拿到这个BeanDefinition后,如何将其初始化。

上一篇博客,讲了下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为我们简化了开发的很多步骤,阅读源码又是个挺困难过程。希望能坚持下去,一一弄清楚一系列平常开发所接触不到的问题。

目录
相关文章
|
11月前
|
Java Spring
创建名为 'authFilterRegistration' 的bean时,该bean依赖于一个未满足的依赖关系
创建名为 'authFilterRegistration' 的bean时,该bean依赖于一个未满足的依赖关系
56 1
|
4月前
|
存储 Java 程序员
【JVM】类的声明周期(加载、连接、初始化)
【JVM】类的声明周期(加载、连接、初始化)
28 1
|
3月前
|
Java 编译器
全面解析JVM加载中初始化的时机
全面解析JVM加载中初始化的时机
|
4月前
|
Java 容器 Spring
SpringBoot:Bean生命周期自定义初始化和销毁
SpringBoot:Bean生命周期自定义初始化和销毁
141 1
|
4月前
|
存储 安全 Java
Trembling ! Java类的加载过程详解(加载验证准备解析初始化使用卸载)
Trembling ! Java类的加载过程详解(加载验证准备解析初始化使用卸载)
53 0
|
Java Spring
任何 bean 初始化回调前自定义逻辑
任何 bean 初始化回调前自定义逻辑
|
消息中间件 存储 安全
类是如何加载的?
类是如何加载的?
114 0
|
JSON API 开发工具
AdonisJs项目初始化
AdonisJs项目初始化
64 0
|
Java 容器 Spring
Bean的加载方式
Bean的加载方式 1.XML方式声明bean 2.XML+注解方式声明bean 3.注解方式声明配置类 扩展1——FactoryBean 扩展2——配置类中导入原始的配置文件(系统迁移) 扩展3——proxyBeanMethods 4.使用@Import导入要注入的bean 扩展4——使用@Import注解还可以导入配置类 5.使用上下文对象在容器初始化完毕后注入bean 6.导入实现了ImportSelector接口的类,实现对导入源的编程式处理 bean的加载方式(七) bean的加载方式(八)
164 1
一个简单的页面加载管理类(包含加载中,加载失败,数据为空,加载成功)(上)
在最近公布的比赛框架中,发现了页面加载管理类,觉得挺有用的,所以做个简单的笔记。
93 0
一个简单的页面加载管理类(包含加载中,加载失败,数据为空,加载成功)(上)