栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring中Lazy、Scope注解对IOC容器Bean初始化的影响分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring中Lazy、Scope注解对IOC容器Bean初始化的影响分析

面试的时候总是会遇到各种Spring主要功能点的问题,因为Spring对于java来说太重要。如Spring的IOC容器、动态代理、事务、切面编程等等。后期再更新文章的时候我们会慢慢讨论这些东西,这里现在我们先看其中一个功能点IOC容器,其实也不算是说IOC容器,主要的重点是放在Spring注解对IOC容器初始化的影响。也是在面试中最常说漏的。

面试模拟

面试官:小明,看你的简历中说对Spring有熟练的理解,那问你一个关于Spring IOC容器的问题。
小明:嗯!
面试官:我们在Spring中都会使用到IOC容器,那就说一下IOC初始化的基本实现原理吧。
小明:在项目启动的时候,Spring会去创建并加载对象到IOC容器中,在加载的过程可以通过以下几种方式,xml、Configuration……
面试官:嗯,说的挺好的,但是如果我在创建bean的时候,使用Scope和Lazy注解,你能解释以下这两个注解对初始化bean有什么影响。
小明:……不太清楚。

总结

小明很明显对IOC容器的初始化理解还是很不错的,但是理解的都是普通模式下情景,却没有理解到外界会对这个过程的影响,也就是太片面。关于Scope和Lazy注解到底对Spring的IOC容器的初始化有什么影响呢。

Scope注解的使用

@Scope注解在项目中很少用到,但是实际上底层是用到的,不过是给了默认的值。

Scope注解属性

先瞅瞅源码:

@AliasFor("scopeName")
String value() default "";


@AliasFor("value")
String scopeName() default "";

scopeName对应的值有四个分别是:

singleton,单例模式,这个也是默认的模式prototype,多例模式,表示每次使用这个对象都是新创建的request,每次请求对应一个实例,针对web应用session,每个会话对应一个实例,针对web应用

这里对session、request模式不做太多说明,博友们有兴趣可以自己研究一下。

案例说明@Scope

直接上代码,一切都不是问题。

public class Person {

    public String name;
    public Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

@Configuration
public class ScopeConfiguration {
    @Bean("person") //创建bean,bean的名称是person
    //@Scope("prototype")
    public Person person() {
        System.out.println("===>初始化bean");
        return new Person("zdydoit", 22);
    }
}

public class ScopeConfigurationTest {

    @Test
    public void scopeTest() {
    	//加载配置类
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(ScopeConfiguration.class);
        System.out.println("===>配置类加载结束");
        //获取bean对象
        Person person1 = (Person) app.getBean("person");
        Person person2 = (Person) app.getBean("person");
        System.out.println(person1);
        System.out.println(person2);
        System.out.println("===>"+(person1==person2);
    }
}

运行测试类的结果如下:

===>初始化bean
===>配置类加载结束
Person{name='zdydoit', age=22}
Person{name='zdydoit', age=22}
===>true

从运行的结果可以看出来,在IOC容器初始化结束之前,初始化bean就已经完成,并且在判断两次获取到的person实例是否相等时,得到的返回值是true,这个就说明当@Scope为singleton的时候,在容器加载的时候就会将bean创建好并放到IOC容器中,等待被获取使用,bean对象是单例的。
现在将配置类上注释掉的@Scope放开,此时再运行一下测试类的代码得到的结果如下:

===>配置类加载结束
===>初始化bean
===>初始化bean
Person{name='zdydoit', age=22}
Person{name='zdydoit', age=22}
===>false

和上面结果不同的是,有两次初始化bean,并且初始化bean都是在IOC初始化结束后才执行的,判断两次获取到的bean对象是否相等,返回的是false,可以很明确的知道,两个对象不是同一个。结论就是在IOC容器初始化的时候对于@Scope为prototype时,不会立即创建对象,而是每次使用的时候创建,并且每次都是创建新的对象,之前创建的不复用。

案例说明@Lazy
// 实体类还是使用之前的Person

@Configuration
public class LazyConfiguration {

    @Bean("person")
    @Lazy
    public Person person() {
        System.out.println("===>bean对象初始化");
        return new Person("zdydoit", 18);
    }
}

public class LazyConfigurationTest {

    @Test
    public void testLazy() {
        ApplicationContext app = new AnnotationConfigApplicationContext(LazyConfiguration.class);
        System.out.println("===>配置类初始化结束");
        Person person1 = (Person) app.getBean("person");
        Person person2 = (Person) app.getBean("person");
        System.out.println(person1);
        System.out.println(person2);
        System.out.println("===>" + (person1 == person2));
    }
}

运行测试类得到的结果如下:

===>配置类初始化结束
===>bean对象初始化
Person{name='zdydoit', age=18}
Person{name='zdydoit', age=18}
===>true

bean的初始化是在IOC容器初始化结束以后执行的,也就是在getBean()执行的时候才去做bean的初始化,当第二次getBean()的时候就不会再去初始化,而是采用的第一次bean初始化的对象,最终两个bean的等于判断也是相等的,由此可以看来@Lazy就相当于懒汉模式,第一次请求创建bean,然后bean会被放入到IOC容器中,后续请求直接使用。

总结

从上面分析看的出来,在Spring容器初始化的时候,并不会把所有的对象都初始化并放到容器中,对于@Scope("prototype")和@Lazy,都是使用的时候去创建,两个不同之处在于一个创建多个(多例),一个创建单个(单例)。
从上面的分析,如果在面试的时候问到Spring的IOC容器初始化,是不是又多了一些可以说(zhuang)的机会了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/770545.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号