Spring中Bean的作用域

作用域分级

一、被声明为singleton的bean

  如果bean的作用域的属性被声明为singleton,那么Spring Ioc容器只会创建一个共享的bean实例。对于所有的bean请求,只要id与该bean定义的相匹配,那么Spring在每次需要时都返回同一个bean实例。  

  Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,singleton作用域是Spring中的缺省作用域。你可以在 bean 的配置文件中设置作用域的属性为 singleton,如下所示:

<bean id="course" class="entity.Course" scope="singleton">

  测试是否是单例模式:

@Test
    public void singleton() {
        Course course1=(Course)context.getBean("course");
        Course course2=(Course)context.getBean("course");
        System.out.println(course1==course2);
    }

信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
true

  在Spring容器中获取单例对象时,会将单例对象放入堆中,后续在栈中无论增加多少对象,内存地址都是指向堆中这个单例对象。

    通过在Course类的有参构造和无参构造中打上标记可以发现,单例模式下容器在初始化时就会创建对象,getBean并不会产生新的对象。

 

@Lazy
public class Course {
    private String couName;
    private Integer couHour;
    private Teacher teacher;
        public Course() {
        super();
        System.out.println("无参");
    }
    
    public Course(String couName, Integer couHour, Teacher teacher) {
        super();
        this.couName = couName;
        this.couHour = couHour;
        this.teacher = teacher;
        System.out.println("有参");
    }
}

 

  @Lazy 可以使单例模式的Bean延迟加载,并不会在初始化下就加载,只会在第一次使用时产生。

  SpringBoot中100多个自动装配类可能就用到了这个懒加载。

 

二、被声明为prototype的bean 

  当一个bean的作用域为prototype,表示一个bean定义对应多个对象实例。声明为prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。

<bean id="course" class="entity.Course" scope="prototype">

@Test
    public void singleton() {
        Course course1=(Course)context.getBean("course");
        Course course2=(Course)context.getBean("course");
        System.out.println(course1==course2);
    }

信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
false

  说明在prototype中就会一直获取新的对象。

    通过在Course类的有参构造和无参构造中打上标记可以发现,多例模式下容器在初始化时并不会创建对象,每次getBean都会产生新的对象。

三、被声明为request的bean

  request,session和application这三个作用域都是基于web的Spring WebApplicationContext实现的,只有在web环境下(比如XmlWebApplicationContext)中才能使用。 
  如果开发者仅仅在常规的Spring IoC容器中比如ClassPathXmlApplicationContext在中使用这些作用域,那么将会抛出一个IllegalStateException来说明使用了未知的作用域。
  配置好web条件后,测试request作用域:

<bean id="course" class="entity.Course" scope="request"> 

  Spring容器会在每次用到Course来处理每个HTTP请求的时候都会创建一个新的Course实例。也就是说,CourseBean的作用域是HTTP Request级别的。 
  当http请求调用作用域为request的bean的时候,每增加一个HTTP请求,Spring就会创建一个新的bean,在请求处理完成之后便及时销毁这个bean。开发者可以随意改变实例的状态,因为通过Course请求来创建的其他实例根本看不到开发者改变的实例状态,所有创建的Bean实例都是根据独立的请求来的。
  由此推断,session就是对话区的作用域,application就是全局的作用域,从网上了解到还可以自定义作用域。

参考:https://blog.csdn.net/kongmin_123/article/details/82048392

posted on 2020-04-02 14:23  18岁程序员想当歌手  阅读(226)  评论(0)    收藏  举报