当前位置:网站首页>Bean 作⽤域和⽣命周期

Bean 作⽤域和⽣命周期

2022-07-07 07:13:00 Youcan.

目录

1. Bean被修改案例

2. 作用域定义

2.1 Bean的6种作用域

2.1.1 singleton 单例作用域

2.1.2 prototype  原型作用域(多例作用域)

2.1.3 request 请求作用域

2.1.4 session 会话作用域

2.1.5 application 全局作用域 (了解即可)

2.1.6 websocket(了解即可)

2.2 设置作用域

3. Bean 原理分析

3.1 Spring 执行流程

3.2 Bean 生命周期

3.2.1 实例化 (在城市买房)

3.2.2 设置属性(装修)

3.2.3 Bean 初始化(买各种新的家具)

3.2.4 使用Bean(入住)

3.2.5 销毁Bean(卖出去)


1. Bean被修改案例

有一个公共的Bean ,A 用户和B用户共同使用, 如果A在使用的时候,将公共资源Bean修改了,会导致B用户在使用时发生错误。

A用户(Controller9)使用的时候进行了修改操作: 

@Controller
public class UserController9 {
    @Autowired
    private User user1;

    public User getUser() {
        User user = user1;
        user.setName("唐僧");
        return user;
    }
}

B用户(Controller9) 使用公共资源:

@Controller
public class UserController10 {
    @Autowired
    private User user1;

    public User getUser() {
        return user1;
    }
}
public class User {
    private int id;
    private String name;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
public class App {
    public static void main(String[] args) {
        // 1. 获取spring上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        UserController9 userController9 = context.getBean(UserController9.class);
        System.out.println("Controller9 : " + userController9.getUser());

        UserController10 userController10 = context.getBean(UserController10.class);
        System.out.println("Controller10 : " + userController10.getUser());
    }
}

输出:Controller9 : User{id=1, name='唐僧', password='123'}
      Controller10 : User{id=1, name='唐僧', password='123'}

实际上我们想让Controller10 输出 :Controller10 : User{id=1, name='张三', password='123'}

public class App {
    public static void main(String[] args) {
        // 1. 获取spring上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");

        if(userController9 == userController9_2) {
            System.out.println("内存地址相等,单例模式");
            System.out.println(userController9);
            System.out.println(userController9_2);
        } else {
            System.out.println("内存地址不相等,非单例模式");
            System.out.println(userController9);
            System.out.println(userController9_2);
        }
    }
}

输出:
内存地址相等,单例模式
[email protected]
[email protected]

使用单例模式会很大程度上提高性能,所以spring中Bean的作用域默认是单例模式(singleton)。也就是所有的人都是用的是同一个对象。

2. 作用域定义

经过上述问题的发生,限定了程序中变量的可用范围,即就是定义了作用域

Bean的作用域是指 Bean在Spring 整个框架中的某种行为模式,比如单例作用域,就表示Bean在整个Spring 中只有一份,并且它是全局共享的,别人修改了这个值之后,后面的人读取到的都是被修改之后的值。

2.1 Bean的6种作用域

Spring 容器在初始化一个Bean 的实例时,同时会指定该实例的作用域。

1. singleton :单例作用域

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

3. request :请求作用域

4. session : 会话作用域

5. application :全局作用域

6. websocket :HTTP WebSocket 作用域

前两种是Spring核心作用域,后四种是Spring MVC 中的作用域

2.1.1 singleton 单例作用域

 描述: 该作用域下的Bean在loC容器中只存在一个实例获取Bean(applicationContext.getBean等方法)及 装配Bean (通过@Autowired注⼊)都是同一个对象。

  场景:无状态的Bean 使用该作用域,无状态表示Bean 对象的属性状态不需要更新

Spring 默认选择该作用域 

2.1.2 prototype  原型作用域(多例作用域)

描述:每次对该作用域下的Bean 的请求都会创建新的实例:获取Bean和装配Bean都是心得对象实例。 

场景:有状态的Bean 使用该作用域 

2.1.3 request 请求作用域

描述:每次 http 请求会创建新的Bean 实例,类似于prototype

 场景:一次http 得请求和响应的共享Bean

  在SpringMVC中使用

2.1.4 session 会话作用域

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

  场景:用户会话的共享Bean ,比如:记录一个用户的登录信息

  在SpringMVC中使用 

2.1.5 application 全局作用域 (了解即可)

2.1.6 websocket(了解即可)

单例作用域(singleton)全局作用域(application)的区别:

 单例作用域是Spring Core (普通项目)的作用域,全局作用域是Spring Web 中的作用域。

 单例作用域作用于loC 的容器,而 全局作用域作用于Servlet 容器。

2.2 设置作用域

 @Scope 标签既可以修饰方法也可以修饰类,@Scope 有两种设置方式:

 1. 直接设置值:@Scope("prototype")

 2. (常量)类似于枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

@Component
public class UserBeans2 {

    @Bean(name = "user1")
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public User user1(){
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123");
        return user;
    }
}
@Controller
public class UserController9 {
    @Autowired
    private User user1;

    public User getUser() {
        User user = user1;
        user.setName("唐僧");
        return user;
    }
}
public class App {
    public static void main(String[] args) {
        // 1. 获取spring上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController9 userController9 = context.getBean(UserController9.class);
        System.out.println("Controller9 : " + userController9.getUser());

        UserController10 userController10 = context.getBean(UserController10.class);
        System.out.println("Controller10 : " + userController10.getUser());

        }
    }
}

输出:Controller9 : User{id=1, name='唐僧', password='123'}
        Controller10 : User{id=1, name='张三', password='123'}

 

修改UserBeans2代码: 

@Component
public class UserBeans2 {

    @Bean(name = "user1")
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public User user1(){
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123");
        return user;
    }
}

输出:

        Controller9 : User{id=1, name='唐僧', password='123'}
        Controller10 : User{id=1, name='唐僧', password='123'} 

 

 

3. Bean 原理分析

3.1 Spring 执行流程

启动Spring 容器 -----》根据配置完成Bean初始化  -----》Bean 对象注册到Spring容器 中 (存)-----》将Bean 装配到需要的类中(取)

3.2 Bean 生命周期

一个对象从诞生到销毁的整个生命过程。

  1. 实例化

  2. 设置属性

  3. Bean 初始化

  4. 使用Bean

  5. 销毁Bean

3.2.1 实例化 (在城市买房)

为Bean分配空间。实例化不等于初始化,只是分配内存空间

3.2.2 设置属性(装修)

执行依赖类的注入和装配(A需要使用B的方法,先初始化,并将B加载到当前类)

3.2.3 Bean 初始化(买各种新的家具)

(1)实现各种Aware 通知方法

(2)执行初始化前置方法

(3)执行初始化方法(两种实现:注解方式@PostConstruct 或 XML<bean init - method='xxx'>

(4)执行自己的指定的init - method 方法

(5)执行初始化后置方法

3.2.4 使用Bean(入住)

3.2.5 销毁Bean(卖出去)

有两种实现:注解方式 @PreDestroy,XML<bean destroy - method='xxx'>

原网站

版权声明
本文为[Youcan.]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_48273471/article/details/125618767