从源码的角度分析@Lazy和@Scope对IOC容器初始化影响以及IOC的总结

在之前的文章中说过lazy、scope对spring ioc容器的初始化影响(Spring中Lazy、Scope注解对IOC容器Bean初始化的影响分析),但是没有具体深入的说,而是通过表面数据判断。另外就是之前也写过spring ioc容器初始化的源码分析(Spring IOC容器初始化基础过程源码了解),这里算是前两篇文章的续集,也是对其补充和做一个总结性的结论。

情景简介

这里就直接进入主题,分别使用@Lazy@Scope("prototype")来修饰两个bean,不会再去做其他的解释,如果这些有不太清晰的,之前博客有写过(Spring中Lazy、Scope注解对IOC容器Bean初始化的影响分析),文章内简称博客一。另外在说源码的时候,不会对内部代码全说且加注释,主在理解主干逻辑。这个源码分析会结合之前的博客一起(Spring IOC容器初始化基础过程源码了解),文章内简称博客二。

源码分析

实例代码

配置类中创建bean的方法:

//配置类
@Configuration
public class AnnotationInit {

    // 单例非懒加载bean
    @Bean("singletonBean")
    public Person person() {
        return new Person("战斗猿singleton", 29);
    }

    //非单例bean
    @Bean("prototypeBean")
    @Scope("prototype")
    public Person prototypePerson() {
        return new Person("战斗猿prototype", 30);
    }

    //单例懒加载bean
    @Bean("lazyBean")
    @Lazy
    public Person lazyPerson() {
        return new Person("战斗猿lazy", 31);
    }
}

测试类中初始化IOC容器代码:

@Test
public void testContext() {
    ApplicationContext app = new AnnotationConfigApplicationContext(AnnotationInit.class);
    Object lazyBean = app.getBean("prototypeBean");
    System.out.println(lazyBean);
}

在通过ApplicationContextgetBean方法中获取bean实例,bean信息的存储都是在beanFactory中,来看看IOC完成初始化后beanFactory的信息。

beanFacotry内的成员变量信息:

在这里插入图片描述

从这个信息可以看出来,被定义到IOC容器中的实例个数是12个,但是真正已经被创建的却只有10个。

beanDefinitionMap内bean的定义信息:

在这里插入图片描述

在配置类中需要创建的bean都定义到了beanFactory中的beanDefinitionMap集合内。

alreadyCreated内创建完成的bean实例信息:

在这里插入图片描述

这里只有单例的bean创建完成并加载进去了,另外的懒加载和非单例bean并没有初始化并加载进来。

getBean()源码

这里getBean源码在博客二中都说过,这里直接进入内部的doGetBean()方法,在AbstractBeanFactory类中。

protected <T> T doGetBean(
        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {

    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    // 代码已:这里是根据beanName获取bean实例
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // ……
    } else {
        // ……
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            // 获取bean的定义信息
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // ……

            // Create bean instance.
            // 创建bean,会做是否为单例bean的判断
            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);
            } else if (mbd.isPrototype()) { // 非单例创建逻辑
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }else {
                // ……
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // ……
    return (T) bean;
}

mbd.isSingleton()对是否为单例做了判断,当是单例bean的时候,执行的流程就是创建bean,然后将bean加入的IOC容器中,在博客二中都说明清楚了。这里需要说明的是,在博客二中我们说的是只做单例非懒加载bean的创建。

//判断逻辑,spring4源代码DefaultListableBeanFactory类中733行,在博客二中也有对这里进行说明
if(!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()){
    ……
}

当这里通过主动调用getBean,如果单例bean没有创建,还是走到同样的单例bean创建代码块。可见只要是单例bean的创建,不论是懒加载还是非懒加载,最终都会通过同样的逻辑创建并放到IOC容器中,只是时机不同,一个是在容器初始化的时候,一个是在bean被需要使用获取的时候。

到这里@Lazy修饰的bean创建时机就很好理解啦。

同样是上面的代码,mbd.isPrototype()做了是否为非单例的判断,如果判断是单例走的就是这一块代码,代码的内部就不去详细的说了,这里只是做bean的创建,然后将bean返回,并没有将bean存储到容器中。

到这里@Scope("prototype")修饰的bean创建时机就很好理解啦。

最终总结

总结项
  • ApplictionContext的构造方法中,通过refresh()方法,做IOC整体的初始化,另外将单例非懒加载bean的创建并加入到IOC容器中。
  • 在使用getBean方法获取单例懒加载bean的时候,和非懒加载bean的逻辑相同,最终创建好的bean也会被放到IOC容器中。
  • 在使用getBean方法获取非单例bean的时候,只会通过另外的逻辑创建bean,并将bean返回给调用方,最终创建好的bean是不会放到IOC容器中的,每次获取都是新创建的bean。
图文解释

用图来解释一下,也许会更清晰一点。

在这里插入图片描述

非单例是虚线部分,看出来,就是绕过了一个getSingleton方法的封装,而是直接调用createBean,为什么绕过,因为在getSingleton封装了向IOC容器里面加入bean的逻辑,而非单例,是每次创建都是最新的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿洞晓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值