bean的作用域和生命周期

一、bean的作用域

Spring中,那些组成应用程序的主体及由 Spring IOC容器所管理的对象,被称之为 bean

简单地讲,bean就是由 IOC容器初始化、装配及管理的对象。

而作用域代表的 bean的创建存在方式,可以在哪里使用

我们分别可以使用以下这四种情况

scope取值 含义 创建对象的时机
singleton(默认) 在一个IOC容器中,这个 bean对象只有一个实例 IOC容器初始时创建单例 bean
prototype 在一个IOC容器中,这个 bean有多个实例 获取 bean的时候
request 每一次 http请求,都会创建一个 bean 每一次 http请求的时候
session 同一个 http session中,有且仅有一个 bean 产生新的 http session会话的时候

后面两种不做要求,仅用在基于 webSpring ApplicationContext环境


演示 singletonprototype的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 package com.banmoon.test.scope;
 
 import com.banmoon.test.User;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Scope;
 
 @Configuration
 public class BeanScope {
 
     @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
     @Bean(name = "user")
     public User user() {
         return new User(1, "banmoon");
    }
 
     public static void main(String[] args) {
         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanScope.class);
         User user = context.getBean(User.class);
         System.out.println(user);
         System.out.println("========== 分割线 ==========");
         // 再次获取user
         User user1 = context.getBean(User.class);
         System.out.println(user1);
    }
 
 }

单例启动,结果如下,两次对象地址打印是一致的

image-20230222092536815

@Scope注解的值改为 prototype

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 package com.banmoon.test.scope;
 
 import com.banmoon.test.User;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Scope;
 
 @Configuration
 public class BeanScope {
 
     @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
     @Bean(name = "user")
     public User user() {
         return new User(1, "banmoon");
    }
 
     public static void main(String[] args) {
         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanScope.class);
         User user = context.getBean(User.class);
         System.out.println(user);
         System.out.println("========== 分割线 ==========");
         // 再次获取user
         User user1 = context.getBean(User.class);
         System.out.println(user1);
    }
 
 }

可以看到他们的地址是不一致的

image-20230222092738236

还有一点,注意上面 spring打印的 debug日志,可以清楚的看到 bean创建的时间节点,

单例 bean是在 IOC容器初始化后,马上就进行了创建

原型 bean是在每次创建时才进行创建,这也是每次获取不一致的原因所在

二、bean的生命周期

什么是 bean的生命周期,就是一个 bean从出生到死亡的过程,其中经历了哪些步骤,了解这些步骤,我们就可以更加清晰了解 bean的运行规律。

总的来说,bean的生命周期可以规划为下面这个步骤

  1. 初始化,也就是调用构造方法

  2. 通过 set方法进行赋值

  3. 处理 Aware系列接口,具体可以查看它的几个子接口具体是做什么的

  4. InitializingBean接口,调用其初始化方法

  5. 调用在 bean标签中指定的初始化方法

  6. 初始化完成,进行使用

  7. DisposableBean接口,调用其销毁方法

  8. 调用在 bean标签中指定的销毁方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 package com.banmoon.test.lifecycle;
 
 import lombok.Getter;
 import org.springframework.beans.factory.BeanNameAware;
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
 
 /**
  * @author banmoon
  */
 @Getter
 public class User implements InitializingBean, DisposableBean, BeanNameAware {
 
     private String name;
 
     public User() {
         System.out.println("1、调用无参构造进行创建");
    }
 
     public void setName(String name) {
         System.out.println("2、通过set方法进行设置属性");
         this.name = name;
    }
 
     @Override
     public void setBeanName(String s) {
         System.out.println("3、Aware系列接口,处理相关的逻辑");
    }
 
     @Override
     public void afterPropertiesSet() throws Exception {
         System.out.println("4、InitializingBean接口,初始化方法");
    }
 
     public void myInit() {
         System.out.println("5、在bean标签中指定的初始化方法");
    }
 
     @Override
     public void destroy() throws Exception {
         System.out.println("7、DisposableBean接口,销毁方法");
    }
 
     public void myDestroy() {
         System.out.println("8、在bean标签中指定的销毁方法");
    }
 
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 package com.banmoon.test.lifecycle;
 
 import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 import org.springframework.context.annotation.Bean;
 
 public class Main {
 
     @Bean(name = "user", initMethod = "myInit", destroyMethod = "myDestroy")
     public User user() {
         User user = new User();
         user.setName("user");
         return user;
    }
 
     public static void main(String[] args) {
         AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
         User bean = context.getBean("user", User.class);
         System.out.println("6、进行模拟使用:" + bean.getName());
         context.close();
    }
 
 }

代码比较简单,直接查看运行结果

image-20230223214903480