谈谈Spring中bean的作用域和生命周期

目录

1.通过一个案例来了解bean的作用域

2.Bean的作用域

1.singleton 单例作用域(spring 的默认)

2.prototype 原型作用域

3.request 请求作用域

4.session 回话作用域

5.applicaiton 全局作用域

6.websocket 作用域

singleton单例作用域和application作用域的区别

3.Bean的执行流程

4.Bean的生命周期

5.生命周期演示


1.通过一个案例来了解bean的作用域

假设现在有一个公共的bean,供A B 两个用户来使用,但是在使用过程中,由于A修改了bean的值,导致下一次B所读到的值是已经被修改的值。这就是由于bean的作用于是全局共享,出现了这个问题。

公共的Bean:

@Component
public class Users {
    @Bean
    public User user1() {
        User user = new User();
        user.setId(1);
        user.setName("Java"); // 【重点:名称是 Java】
        return user;
    }
}

A用户使用的同时修改了Bean:

@Controller
    public class BeanScopesController {
    @Autowired
    private User user1;
    public User getUser1() {
        User user = user1;
        System.out.println("Bean 原 Name:" + user.getName());
        user.setName("悟空"); // 【重点:进行了修改操作】
        return user;
    }
}

B用户再次使用Bean:

@Controller
    public class BeanScopesController2 {
    @Autowired
    private User user1;
    public User getUser1() {
        User user = user1;
        return user;
    }
}    

打印A B两个用户此时所拥有公共Bean的值:

public class BeanScopesTest {
    public static void main(String[] args) {
    ApplicationContext context = new
        ClassPathXmlApplicationContext("spring-config.xml");
    BeanScopesController beanScopesController =
        context.getBean(BeanScopesController.class);
        System.out.println("A 对象修改之后 Name:" +
        beanScopesController.getUser1().toString());
        BeanScopesController2 beanScopesController2 =
        context.getBean(BeanScopesController2.class);
        System.out.println("B 对象读取到的 Name:" +
        beanScopesController2.getUser1().toString());
    }
}

 结果:

此时由于这个公共的Bean对象的作用域默认是单例模式,所有人使用的都是同一个对象,所有对象都可以修改,因此发生了变化,那么Bean的作用域有哪些呢?我们接着往下看!

2.Bean的作用域

Spring容器在初始化一个Bean对象时会,同时会指定该Bean的作用域,Spring的作用域有如下六种:

  1. singleton:单例作用域
  2. prototype:原型作用域
  3. request:请求作用域
  4. session:回话作用域
  5. applicaition:全局作用域
  6. websocket:HTTP websocket作用域

注意 :在普通的Spring 中只有前两种,后四个是在Spring mvc的作用域

1.singleton 单例作用域(spring 的默认)

描述:在该作用域下的Bean对象在lOC容器中之村在一个实例对象,获取Bean及配装修改Bean都是同一个对象

场景:通常无状态的Bean使用该作用域,无状态是指Bean的属性不会发生变化

2.prototype 原型作用域

描述:在该作用域下,每次使用Bean对象都会创建新的实例,获取Bean和配装修改Bean都是新的实例,不是同一个对象。

场景:通常使用的是有状态的Bean

3.request 请求作用域

描述:每一个http请求会创建新的Bean实例

场景:一次请求和响应共享一个Bean,该作用域只限定于Spring mvc

4.session 回话作用域

描述:在一个http session 中创建一个Bean实例

场景:用户会话的共享Bean,比如记录一个用户的登录信息,该作用域只限定于Spring mvc

5.applicaiton 全局作用域

描述:在一个http servlet context 中定义一个Bean实例

场景:web应用的上下文信息,该作用域只限定于Spring mvc

6.websocket 作用域

描述:在一个HTTP WebSocket的生命周期中,定义一个Bean实例
场景:WebSocket的每次会话中,保存了一个Map结构的头信息,将用来包裹客户端消息头。第一次初始化后,直到WebSocket结束都是同一个Bean。 

singleton单例作用域和application作用域的区别

  1. singleton是spring core的作用域;application是spring web 的作用域

  2. singleton作用于lOC容器当中,application作用域servlet容器当中

3.Bean的执行流程

要了解Bean的生命周期,我们先来了解Bean是如何执行的:

所以Bean的执行流程:启动Spring容器 ->  实例化Bean(分配内存空间,从无到有)-> Bean 注册到 Spring 中(存操作) -> 将 Bean 装配到需要的类中(取操作)。

4.Bean的生命周期

所谓的生命周期指的是一个对象从诞生到销毁的整个生命过程,我们把这个过程就叫做一个对象的生命周期。

Bean 的生命周期分为以下 5 大部分:

  1. 实例化 Bean(为 Bean 分配内存空间):通过反射调用构造方法来实现实例化
  2. 设置属性:Bean 注入和装配
  3. Bean 初始化
    1. 实现了各种 Aware 通知的方法如:BeanNameAware、BeanFactoryAware、ApplicationContextAware 的接口方法;
    2. Bean对象初始化前,循环调用了BeanPostProcessor接口的预初始化方法(postProcessBeforeInitialization);
    3. 执行 @PostConstruct 初始化方法,依赖注入操作之后被执行;
    4. 执行自己指定的 init-method 方法(如果有指定的话);
    5. Bean对象初始化后,循环调用了BeanPostProcessor接口的后初始化方法(postProcessAfterInitialization)
  4. 使用 Bean
  5. 销毁 Bean 销毁容器的各种方法,如
    • @PreDestroy、DisposableBean 接口方法、destroy-method。

具体的执行流程如下图:

5.生命周期演示

package com.example.lifecycle;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class BeanLifeComponent implements BeanNameAware {
    @PostConstruct
    public void postConstruct() {
        System.out.println("执行 PostConstruct()");
    }
    public void init() {
        System.out.println("执行 BeanLifeComponent init-method");
    }
    @PreDestroy
    public void preDestroy() {
        System.out.println("执行:preDestroy()");
    }
    public void setBeanName(String s) {
        System.out.println("执行了 setBeanName 方法:" + s);
    }
}

主方法:

package com.example;

import com.example.lifecycle.BeanLifeComponent;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class MainLifeCycle {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        BeanLifeComponent life = context.getBean(BeanLifeComponent.class);
        System.out.println("执行 main 方法");
// 执行销毁方法
        context.destroy();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值