Bean的作用域和生命周期

变量的作用域
变量的作用域是指一个变量生效的范围,作用的范围。比如定义了一个类变量,就意味着类里面的所有方法都可以使用;如果变量定义在方法里面,就称为方法变量,方法变量只能在方法里面去使用。

Bean的作用域

Bean是Spring里面存储的对象,Bean的作用域指的是Bean对象在Spring容器里面的行为
下面我们用一个例子来看Bean作用域问题:

  • 我们先创建一个公共类Users,调用getUser()方法可以或得一个公共的User对象,我们设置这个公共类的User的id为222,User的name为李四:
package com.java.demo.model;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
// 公共类
@Component
public class Users {
    @Bean("user")
    public  User getUser(){
         User user=new User();
         user.setId(222);
         getUser().setName("李四");
         return  user;
    }
}

  • 假设有两个人需要对这个公共类进行改进,在这里我们用UserController2和UserController3来代表这两个人。
  • UserController2对公共对象的操作如下:
import com.java.demo.model.User;
import com.java.demo.model.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController2 {
    @Autowired
    private User user;
    public  void doMethod(){
        User  user2=user;
        System.out.println("UserController2修改之前"+user);
        user2.setName("张三");
        user2.setId(1111);
        System.out.println("UserController2修改之前:"+user);
    }
}

UserController2先定义了一个User类型的变量user2然后将user给user2,然后打印了一下修改之前的user,接着对user2进行id设置和name设置,最后打印一下修改后的user。
Bean的作用域和生命周期_第1张图片可以看到,公共对象user已经被修改了,id和name都被UserController2进行了修改。虽然UserController2是对user2进行了操作,可是还是改变了原本的user。
我们再看一下 UserController3:

package com.java.demo.controller;

import com.java.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

@Controller
public class UserController3 {
    @Autowired
    private User user;
    public void doMethod(){
        System.out.println("UserController3 的user:"+user);
    }
}

UserController3并没有对公共对象user进行任和操作,只是在doMethod方法里面打印了一下公共对象user。UserController3希望拿到的user是没有被改动的user,那我们来看一下代码执行的结果(我们在main方法里面,先调用UserController2的doMethod方法,再调用UserController3的doMethod方法):
Bean的作用域和生命周期_第2张图片代码执行结果:
Bean的作用域和生命周期_第3张图片
结果发现,虽然UserController2重新定义了一个变量,然后进行修改,但是原来的公共对象依旧被改动了,导致UserController3拿到的公共对象user已经是被改动后的了。
导致这样结果的原因就是:

  private User user;
   User  user2=user;

这里代码实际上定义一个User类型的变量,这个变量指向的是user对象,并没有新的对象。这时候使用user2去修改对象的时候,就相当于修改了user对象。
归根结底导致这个问题的原因就是Bean的作用域,Bean对象默认的是单例模式。(单例模式是指在程序的运行期间只有一份)。

  • 如何避免默认单例模式带来的问题?
    手动设置,通过@Scope注解,如@Scope(“prototype”)、prototype就是原型模式:
package com.java.demo.model;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
// 公共类
@Component
public class Users {
    @Bean
    @Scope("prototype")
    public  User getUser(){
         User user=new User();
         user.setId(222);
        user.setName("李四");
         return  user;
    }
}

Bean的作用域和生命周期_第4张图片

Bean作用域类型:
概念:Bean作用域指的是Bean在Spring容器中的某种行为,比如单例模式,比如原型模式等。

  1. singleton:单例作用域(默认的作用域)
    补充问题:单例模式的Bean是线程安全的吗?不是,因为所有人都可以操作这个公共变量,所以不是线程安全的,使用ThreadLocal可以变成线程安全的。
  2. prototype:原型作用域(多例模式)
  3. request:请求作用域,只适用于Spring MVC项目(就是Spring Web项目)
  4. session:回话作用域,一个Http会话共享一个Bean,是适用于Spring MVC项目。
  5. application:全局作用域,表示的是一个Context容器共享一个作用域。只适用于Spring MVC项目。
  6. websocket:Http WebSocket作用域,只适用于Webscoket作用域。

Spring的生命周期

  1. 启动容器
  2. 读取配置文件,进行Bean的实例化
  3. 将Bean加入到容器中
  4. 装配Bean属性(给当前类的属性赋值)

Bean的生命周期

  1. 实例化(内存空间的分配)
  2. 设置Bean属性(进行依赖注入,将依赖的Bean赋值到当前类的属性上)
  3. Bean的初始化
    3.1 执行各种通知
    3.2 初始化的前置方法
    3.3 初始化方法
    3.4 初始化的后置方法
  4. 使用Bean
  5. 销毁Bean

你可能感兴趣的:(spring)