美文网首页
spring被@Bean注解的方法是如何变成SpringBean

spring被@Bean注解的方法是如何变成SpringBean

作者: 黑铁大魔王 | 来源:发表于2020-07-05 22:39 被阅读0次

    上一篇文章写到了被@Bean注解的方法如何转变成beanDef,进入bdMap的
    现在继续来跟进beanDef是如何转变成为真正的SpringBean的
    先上一段Spring源码阅读经典代码

    @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing.
                prepareRefresh();
    
                // Tell the subclass to refresh the internal bean factory.
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
                // Prepare the bean factory for use in this context.
                prepareBeanFactory(beanFactory);
    
                try {
                    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    
                    // Invoke factory processors registered as beans in the context.
                    invokeBeanFactoryPostProcessors(beanFactory);
    
                    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
    
                    // Initialize message source for this context.
                    initMessageSource();
    
                    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    
                    // Initialize other special beans in specific context subclasses.
                    onRefresh(); // springboot依赖starter-web后,里会进入AbstractApplicationContext子类AnnotationConfigServletWebServerApplicationContext里的onRefresh(),进而启动web容器
    
                    // Check for listener beans and register them.
                    registerListeners();
    
                    // Instantiate all remaining (non-lazy-init) singletons.
                    // 这里会生成SpringBean对象,跟进去看即可
                    finishBeanFactoryInitialization(beanFactory);
    
                    // Last step: publish corresponding event.
                    finishRefresh();
                }
    。。。
    

    从bdMap里拿到需要被制作成SpringBean的beanDef

    上面12个方法的第11个,也就是倒数第二个finishBeanFactoryInitialization(beanFactory);方法里,会将beanFactory中的bdMap里的beanDef拿出来实例化,包装,然后放到单利池singletonObjects中。

    finishBeanFactoryInitialization
    从该方法的最后一个调用继续跟进去
    preInstantiateSingletons
    该方法很简单
    1. 首先拿到beanNames列表,
    2. 然后循环实例化每个class,
    3. 通过getBean(beanName)继续进行实例化流程

    getBean(beanName)是个空壳方法,继续调用doGetBean(name, requiredType, args, false);

    doGetBean
    doGetBean
    doGetBean方法里会进行beanName的转换,循环引用的判断与处理,创建单例bean。
    这里314行通过getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法进入,内部再回调lambda表达式里的createBean()方法,完成其后续操作。实际上,创建lambda中高的beanBean(beanName, mbd, args)方法就是真正来创建SpringBean的。
    PS: AbstractBeanFactoryDefaultSingletonBeanRegistry的子类
    那么就直接看createBean()吧。
    getSingleton
    这里传递的singletonFactory是AbstractAutowireCapableBeanFactory,所以,246行的getObject()也就进入下面的截图了
    createBean
    可以看到mbdToUse的属性,大多都是上一篇文章里写的class进入bdMap里面的内容。
    doCreateBean
    doCreateBean方法里,首先create一个beanInstanceWrapper,这是个BeanWrapper对象,也就是说,先把需要处理的class整成一个包装对象instanceWrapper。
    进入createBeanInstance继续看
    createBeanInstance

    生成class的对象

    注意了,在此之前的所有操作,对于@Component,@Service,@Bean是没有区别的,区别从这里开始,因为@Bean注解的方法生成的beanDef,也就是截图里的mbd里的factoryMethodName是有值的。所以会通过instantiateUsingFactoryMethod(beanName, mbd, args)方法来创建 包装对象。
    接下来进入该方法

    instantiateUsingFactoryMethod
    没什么可说的,继续往下跟踪
    instantiateUsingFactoryMethod
    很简单的代码,拿到factoryBeanName,拿到factoryBean,判断factoryBean是否被代理过,如果被代理过,就去拿代理前的对象。箭头指的代码如下
        public static Class<?> getUserClass(Class<?> clazz) {
            if (clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
                Class<?> superclass = clazz.getSuperclass();
                if (superclass != null && superclass != Object.class) {
                    return superclass;
                }
            }
            return clazz;
        }
    

    为什么要那代理前的对象呢?因为474行,需要通过代理前的类获取候选方法。

    image.png
    只有一个方法xyz()能够进入候选方法列表里,然后调用instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS)。注意:这里的factoryBean用的可是代理对象哦。
    image.png
    这个CglibSubclassingInstantiationStrategy是怎么来的呢?其实是事先定义好的。 cglib_instance.gif
    跟踪进入后面的instantiate( mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args)方法里
    image.png
    很简单的来个反射调用,执行xyz()方法里的代码,拿到返回值。
    invoke.gif
    可以看到调用xyz()方法是,在返回实例之前可以执行其他代码。
    result
    区别至此结束,@Bean要生成的的对象搞出来了,下面就是如何生成SpringBean了。

    下面的内容与@Component,@Service等已基本无差别。属于将class的对象制作成SpringBean的内容
    上面代码一路返回,来到这里


    wrapper
    image.png

    得到了包装类型了吧。接着往下来到了非常重要的属性填充环节。


    image.png
    populateBean()
    applyPropertyValues()
    这里的pvs,也就是PropertyValues是空,就直接返回了,不是重点。
    属性填充完毕后,就是初始化bean了
    initializeBean
    initializeBean()

    initializeBean里会调用setXXX()注入的方法,调用后置处理器,调用生命周期重的初始化回调方法,调用后置处理器的postProcessAfterInitialization()方法然后返回wrappedBean,赋值给exposedObject,并且返回exposedObject。


    继续返回
    继续返回
    image.png 继续返回
    这里返回到了getSingletion()里,拿到了SpringBean,然后在282行addSingleton(beanName, singletonObject);里,将其注入到ioc容器
    addSingleton

    相关文章

      网友评论

          本文标题:spring被@Bean注解的方法是如何变成SpringBean

          本文链接:https://www.haomeiwen.com/subject/ipwlqktx.html