Spring(四):Bean作用域和生命周期

一、Bean作用域作用域

1.1 Bean作用域简介

现在有一个公共的Bean,A用户先使用到这个Bean,并在使用后将Bean修改了,这就是B用户拿到的Bean是A修改后的Bean了,而B期望拿到的确实最原始的Bean

公共的Bean:User对象

@Component
public class UserBeans {
    @Bean
    public  User user(){
        User user=new User();
        user.setName("zhangsan");
        user.setId(100);
        return  user;
    }
}

A用户使用后将name修改成lisi了:

@Controller
@Controller
public class UserControllerA {

    @Autowired
    private  User user;

    public  User getUser(){
        User tmp=user;
        System.out.println("A用户修改之前的User.name:"+user.getName());
        tmp.setName("lisi");
        return tmp;
    }
}

B用户使用Bean:


@Controller
public class UserControllerB {

    @Autowired
    private  User user;

    public  User getUser(){
        return user;
    }
}

App类打印:
在这里插入图片描述
【原因分析】

产生上述情况的原因在于Bean默认情况下是单例状态,也就是所有人使用的都是同一个对象,之所以默认为单例状态是因为性能更高

1.2 作用域的定义

Bean的作用域是指Bean在Spring整个框架中的某种行为模式,比如singleton单例作用域,就表示Bean在整个Spring中只有一份,它是全局共享的,那么当其他人修改了这个值后,别人获取到的就是修改后的值了

1.3 Bean的6种作用域

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

  1. singleton 单例作用域
  2. prototype 原型作用域
  3. request 请求作用域
  4. session 会话作用域
  5. application 全局作用域
  6. websocket HTTPWebSokcet作用域

【singleton】
描述:在该作用域下的Bean在IoC容器中只存在一个实例:获取Bean及装配Bean都是同一个对象
使用场景:通常无状态的Bean使用该作用域。无状态表示Bean对象的属性状态不需要更新
Spring默认作用域为singleton

【prototype】
描述:每次都过application.getBean方法或通过注解注入Bean时,通过会创建新的实例,得到的都是新创建的对象
使用场景:通常又状态的Bean使用该作用域
【request】
描述:每次http请求都会创建新的Bean实例
使用场景:一次http请求和响应的共享Bean

【session】
描述:在一个http session中,定义一个Bean实例
使用场景:用户会话的共享Bean

【application】
描述:在⼀个http servlet Context中,定义⼀个Bean实例
使用场景:Web应⽤的上下⽂信息,⽐如:记录⼀个应⽤的共享信息

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

【singleton和application的区别】

singleton是SpringCore的作用域,application是Spring Web的作用域
singleton作用于IoC容器,application作用于Servlet容器

1.4 设置作用域

使用@Scope标签生命Bean作用域

@Component
public class UserBeans {
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public  User user(){
        User user=new User();
        user.setName("zhangsan");
        user.setId(100);
        return  user;
    }
}

App中的执行结果:
在这里插入图片描述
【补充】
Scope标签有两种设置方式:

  1. 直接设置值,@Scope(“prototype”)
  2. 使用枚举设置,@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

二、Spring的执行流程和Bean的生命周期

2.1 Spring的执行流程

在这里插入图片描述

2.2 Bean的生命周期

Bean的生命周期分为下面5个部分:

  1. 实例化Bean(为Bean分配内存空间)
  2. 设置属性(Bean注入和装配)
  3. Bean初始化
  • 实现了各种Aware通知的方法,如BeanNameAware、BeanFactoryAware、ApplicationContextAware的接口方法
  • 执行@PostConstruct初始化方法,依赖注入操作之后执行
  • 执行自己指定的init-method方法
  1. 使用Bean
  2. 销毁Bean,销毁容器的各种⽅法,如 @PreDestroy、DisposableBean 接口方法、destroy-method。

执行流程如下图所示:

BeanLifeComponent类:

package com.bit;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;


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()");
    }
    @Override
    public void setBeanName(String s) { //BeanNameAware接口中的方法
        System.out.println("执行BeanName通知");
    }
}

spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:content="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package="com.bit"></content:component-scan>

    <bean id="beanLifeComponent" class="com.bit.BeanLifeComponent" init-method="init"></bean>
</beans>

App启动类:
在这里插入图片描述
【注意】:设置属性一定要在初始化之前,如果步骤颠倒就可能出现空指针异常

@Service
public class UserService {
 public UserService(){
 System.out.println("调⽤ User Service 构造⽅法");
 }
 public void sayHi(){
 System.out.println("User Service SayHi.");
 }
}
@Controller
public class UserController {
 @Resource
 private UserService userService;
 @PostConstruct
 public void postConstruct() {
 userService.sayHi(); //在构造方法中使用到属性userService
 System.out.println("执⾏ User Controller 构造⽅法");
 }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值