Spring框架(四)Spring的Bean作用域和生命周期

一,作用域定义

限定程序中变量的可用范围叫做作用域,而 Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式,比如 singleton 单例作用域,就表示 Bean 在整个 Spring 中只有⼀份,它是全局共享的,那么当其他⼈修改了这个值之后,那么另⼀个⼈读取到的就是被修改的值

二,同⼀类型多个 @Bean 报错的解决办法

  • 方法1:使用正确的bean name 获取
  • 方法2:使用@Resource设置name属性
// 注⼊
@Resource(name = "user1")
private User user;
  • 方法3:使用@Autowired+@Qualifier
// 注⼊
@Autowired
@Qualifier(value = "user2")
private User user;

三,Bean的6种作用域

Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作用域。Spring有 6 种作用域,最后四种是基于 Spring MVC 生效的:

1.singleton:单例作用域

  • 描述:该作用域下的Bean在IoC容器中只存在⼀个实例:获取Bean(即通过
    applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是同⼀
    个对象。
  • 场景:通常无状态的Bean使用该作用域,无状态表示Bean对象的属性状态不需要更新
  • 备注:Spring默认选择该作用域

2.prototype:原型作用域(多例作用域)

  • 描述:每次对该作⽤域下的Bean的请求都会创建新的实例:获取Bean(即通过
  • applicationContext.getBean等⽅法获取)及装配Bean(即通过@Autowired注⼊)都是新的
    对象实例。
  • 场景:通常有状态的Bean使⽤该作⽤

3.request:请求作用域

  • 描述:每次http请求会创建新的Bean实例,类似于prototype
  • 场景:⼀次http的请求和响应的共享Bean
    备注:限定SpringMVC中使⽤

4.session:回话作用域

  • 描述:在⼀个http session中,定义⼀个Bean实例
  • 场景:⽤户回话的共享Bean, ⽐如:记录⼀个⽤户的登陆信息
  • 备注:限定SpringMVC中使⽤

5.application:全局作用域

  • 描述:在⼀个http servlet Context中,定义⼀个Bean实例
  • 场景:Web应⽤的上下⽂信息,⽐如:记录⼀个应⽤的共享信息
  • 备注:限定SpringMVC中使⽤

6.websocket:HTTP WebSocket 作用域

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

7,单例作用域(singleton)和全局作用域(application)区别

  • singleton 是 Spring Core 的作用域;application 是 Spring Web 中的作用域;
  • singleton 作用于 IoC 的容器,而application 作用于 Servlet 容器

四,Spring框架中的单例bean是线程安全的吗

  • 不是,Spring框架中的单例bean不是线程安全的
  • spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。
    实际上大部分时候 spring bean 无状态的(比如 dao 类),所以某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。
    ①有状态就是有数据存储功能。
    ②无状态就是不会保存数据。

五,Spring如何处理线程并发问题

  • 在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题
  • ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式
  • ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal

六,Spring框架中bean的生命周期

  • Bean 执行流程(Spring 执行流程):启动 Spring 容器 -> 实例化 Bean(分配内存空间,从⽆到有)-> Bean 注册到 Spring 中(存操作) -> 将 Bean 装配到需要的类中(取操作)
  • Bean的生命周期:
    1.实例化 Bean(为 Bean 分配内存空间)
    2.设置属性(Bean 注⼊和装配)
    3.Bean 初始化
    实现了各种 Aware 通知的⽅法,如 BeanNameAware、BeanFactoryAware、
    ApplicationContextAware 的接⼝⽅法;
    执⾏ BeanPostProcessor 初始化前置⽅法;
    执⾏ @PostConstruct 初始化⽅法,依赖注⼊操作之后被执⾏;
    执⾏⾃⼰指定的 init-method ⽅法(如果有指定的话);
    执⾏ BeanPostProcessor 初始化后置⽅法。
    4.使用Bean
    5.销毁 Bean
    销毁容器的各种⽅法,如 @PreDestroy、DisposableBean 接⼝⽅法、destroy-method
  • 具体实例:
    ean 的⽣命流程看似繁琐,但咱们可以以⽣活中的场景来理解它,⽐如我们现在需要买⼀栋房⼦,那
    么我们的流程是这样的:
    1.先买房(实例化,从⽆到有);
    2.装修(设置属性);
    3.买家电,如洗⾐机、冰箱、电视、空调等([各种]初始化);
    4.⼊住(使⽤ Bean);
    5.卖出去(Bean 销毁)

七,Bean生命周期演示

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);
    }
}

实例化和初始化的区别:
实例化和属性设置是 Java 级别的系统“事件”,其操作过程不可⼈工预和修改;而初始化是给开发者提供的,可以在实例化之后,类加载完成之前进行自定义“事件”处理

八,哪些是重要的bean生命周期方法? 你能重载它们吗

  • 有两个重要的bean 生命周期方法,第一个是setup , 它是在容器加载bean的时候被调用。第二个方法是 teardown 它是在容器卸载类的时候被调用。
  • bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)
    扩展【什么是Spring的内部bean?什么是Spring inner beans】
    在Spring框架中,当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现,内部bean通常是匿名的,它们的Scope一般是prototype

九,在 Spring中如何注入一个java集合

Spring提供以下几种集合的配置元素:

  • 类型用于注入一列值,允许有相同的值。

  • 类型用于注入一组值,不允许有相同的值。

  • 类型用于注入一组键值对,键和值都可以为任意类型。

  • 类型用于注入一组键值对,键和值都只能为String类型。

十,使用@Autowired注解自动装配的过程是怎样的

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。
在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找;
  • 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

扩展 【自动装配有哪些局限性】
重写:你仍需用 和 配置来定义依赖,意味着总要重写自动装配。
基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜羊羊zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值