Spring注解驱动开发 第三节组件的单实例与多实例

本文深入探讨了Spring框架中组件的单实例与多实例特性。通过实验演示了单实例模式下,组件在Spring容器启动时即被加载并保持唯一;而在多实例模式下,每次请求都会创建新的组件实例。此外,还介绍了懒加载机制如何延迟组件的初始化。
Spring注解驱动开发 第三节组件的单实例与多实例

spring的只要是注入到容器中的默认都是单实例的,我们可以做一个小实验测试一下

@Configuration
public class MainConfig2 {
    /**
     * @see
     *     ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * 	@see ConfigurableBeanFactory#SCOPE_SINGLETON
     * 	@see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
     * 	@see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
     */
    //@Scope("prototype")
    @Bean
    public Person person(){
        return new Person("张三","27");
    }
}

新建了一个MainConfig2配置文件,然后将person注入到spring容器中。

@Test
    public void test02(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        Person person1 = (Person) context.getBean("person");
        Person person2 = (Person) context.getBean("person");

        System.out.println(person1 == person2);
    }

由于spring默认单实例,所以当两次拿到的person时同一个,所以结果为true,下面查看打印结果:

四月 22, 2019 3:19:11 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Mon Apr 22 15:19:11 GMT+08:00 2019]; root of context hierarchy
true

Process finished with exit code 0

果不其然,确实是true,这也证实了spring默认时单实例的。当我再次修改代码,验证spring在单实例的情况下,组件的加载方式是怎样的。

/**
     * @see
     *     ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * 	@see ConfigurableBeanFactory#SCOPE_SINGLETON
     * 	@see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
     * 	@see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
     */
    //@Scope("prototype")
    @Bean
    public Person person(){
        System.out.println("person类被初始化了...");
        return new Person("张三","27");
    }
    @Test
    public void test02(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);

//        System.out.println("spring容器初始化完成");
//
//        Person person1 = (Person) context.getBean("person");
//        Person person2 = (Person) context.getBean("person");
//
//        System.out.println(person1 == person2);
    }

结果:

四月 22, 2019 3:23:50 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Mon Apr 22 15:23:50 GMT+08:00 2019]; root of context hierarchy
person类被初始化了...

Process finished with exit code 0

可以看出,在测试类中,我们只是加载了一下配置类,启动了spring容器,然后这个类就被注入到spring容器中了,在这种场景下,基本可以断定,在spring单实例模式的情况下,在启动spring容器的时候就开始加载类成为spring的组件,以后在从容器中获取实例时都是这个对象,所以每次获取他们都是同一个对象。

多实例实验
/**
     * @see
     *     ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * 	@see ConfigurableBeanFactory#SCOPE_SINGLETON
     * 	@see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
     * 	@see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
     */
    @Scope("prototype")
    @Bean
    public Person person(){
        System.out.println("person类被初始化了...");
        return new Person("张三","27");
    } 
	@Test
    public void test02(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("spring容器初始化完成");
        Person person1 = (Person) context.getBean("person");
        Person person2 = (Person) context.getBean("person");
        System.out.println(person1 == person2);
    }

结果:

四月 22, 2019 3:31:39 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Mon Apr 22 15:31:39 GMT+08:00 2019]; root of context hierarchy
spring容器初始化完成
person类被初始化了...
person类被初始化了...
false

Process finished with exit code 0

可以看出当在组件中加入@Scope(“prototype”)后,spring容器对这个组件就改为多实例的方式,从容器中取出的两个person不是一个对象。所以打印false,然后我们仔细观察一下打印结果的内容,spring容器初始化完成时测试类中的打印语句,所以在启动spring后bean并没有被注入到容器,与单实例完全相反,在getBean的时候才初始化了一个person类,而且每次getBean都会初始化一个person对象,所以他是new了多次的,对比的话肯定不是一个对象,所以返回false。

总结:单实例在启动spring时创建对象,注入到容器,以后获取这个bean都是同一个bean
多实例在启动spring时不创建对象,也不注入容器,获取bean时财创建一个对象并返回,而且每次获取一个对象都会创建一个新的对象

下面在说一说懒加载
    @Lazy
    @Bean
    public Person person(){
        System.out.println("person类被初始化了...");
        return new Person("张三","27");
    }

加入注解@Lazy就可使这个类懒加载到spring容器中。我们查看一下打印结果:

四月 22, 2019 3:45:24 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2f410acf: startup date [Mon Apr 22 15:45:24 GMT+08:00 2019]; root of context hierarchy
spring容器初始化完成
person类被初始化了...
true

Process finished with exit code 0

分析结果:首先在容器启动后我们并未看到person类被加载到容器,而是在getBean的时候才被加载到容器,但是这个person只被加载了一次,最后对比两次获取的person,结果是true,表示他们获取的是同一个对象。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值