Bean的作用域和生命周期

目录

通过一个案例来理解Bean作用域的问题

Bean作用域定义

Bean的6种作用域

1.singleton

2.prototype

3.request

4.session

5.application

6.websocket

Bean的作用域的设置

Spring的执行流程

Bean的生命周期


通过一个案例来理解Bean作用域的问题

打开一个Spring core项目:

创建一个User的实体类:

package com.java.demo.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

//lombok
@Setter
@Getter
@ToString
public class User {
    private int id;
    public String name;
}

创建一个UserBeans类,将User存入Spring容器:

package com.java.demo.component;

import com.java.demo.entity.User;
import com.java.demo.entity.User;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
public class UserBeans {
    @Bean
    public User user() {
        // 伪代码
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}

创建一个UserController类,通过属性注入的方式获取到Bean对象:

在这段代码里获取到对象之后,在方法内部将user赋值给myUser,通过myUser对对象进行修改.

那么这里修改myUser会不会对user产生影响呢?

package com.java.demo.controller;
import com.java.demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import javax.annotation.PostConstruct;
@Controller
public class UserController {

    @Autowired
    private User user;
    public void printUser() {
        System.out.println(user);
        // 修改 User
        User myUser = user;
        myUser.setName("悟空");
        System.out.println("myUser -> " + myUser);
        System.out.println("user -> " + user); 
    }
}

在创建一个UserController2:

在这里我们也获取User对应的Bean对象,我们预期得到的是张三,而不是修改之后的悟空.

package com.java.demo.controller;
import com.java.demo.entity.User;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;
@Controller
public class UserController2 {

    @Resource
    private User user;

    public void printUser2() {
        System.out.println("user -> " + user); 
    }
}

在启动类中获取到controller对象:

import com.java.demo.controller.UserController;
import com.java.demo.controller.UserController2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        UserController userController =
                context.getBean("userController",UserController.class);

        userController.printUser();

        UserController2 userController2 =
                context.getBean("userController2",UserController2.class);
        userController2.printUser2();
    }
}

打印结果:

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

可以看到的是:UserController中myUser和user指向的是同一个对象,所以说都打印了悟空.

从最后一条打印结果可以看到:UserController2 获取的User的Bean对象是修改之后的悟空,而不是预期的张三,也就是说它们得到的是同一个Bean对象.

出现以上问题的原因就是:Bean默认情况下是单例状态,也就是所有人使用的都是同一个对象.使用单例可以很大程度上提高性能,所以在Spring中Bean的作用域默认也是singleton单例模式.


Bean作用域定义

限定程序中变量的可用范围叫做作用域.而Bean的作用域是指Bean在Spring整个框架中的某种行为模式.

比如singleton单例作用域就表示Bean在整个Spring中只有一份,它是全局共享的,当其他人修改了这个值后,另一个人读取到的就是修改之后的值.


Bean的6种作用域

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

Bean作用域(Scope)包括:

1.singleton

单例作用域,默认的作用域,出于性能的考虑.该作用域下的Bean在IoC容器中只存在一个实例.通常无状态的Bean使用该作用域.无状态表示Bean对象的属性状态不需要更新.

2.prototype

原型作用域(多例作用域),每次对该作用域下的Bean的请求都会创建新的实例,及获取Bean和装配Bean都是新的实例.通常有状态的Bean会使用该作用域.

3.request

请求作用域,每次Http请求,都会创建一个Bean对象.适用于Spring MVC/Spring Web.

4.session

会话作用域,每次Session会话共享一个Bean.适用于Spring MVC.

5.application

全局作用域,一个http servlet context 中共享一个Bean.适用于Spring MVC.

6.websocket

HTTP WebSocket作用域,网络长连接,只适用于Spring WebSocket项目.


Bean的作用域的设置

作用域的设置实在存储Bean对象的时候进行设置的,而不是在取的时候.

我们使用@Scope标签就可以来设置Bean的作用域.@Scope标签既可以修饰方法也可以修饰类.

有两种设置方式:

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

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

再次启动测试类:

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


Spring的执行流程

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

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


Bean的生命周期

Bean从诞生到销毁的过程.

1.开辟内存空间:实例化.实例化不等于初始化.

2.设置属性(注入属性)

3.初始化

  •         3.1各种通知
  •         3.2初始化前置方法
  •         3.3初始化方法(两种实现方式:xml方式或者是注解的方式)
  •         3.4初始化后置方法

4.使用Bean

5.销毁Bean对象


代码演示:

package com.java.demo.component;
import org.springframework.beans.factory.BeanNameAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class BeanComponent implements BeanNameAware {
    @Override
    public void setBeanName(String s) {
        System.out.println("执行了通知 BeanName ->" + s );
    }

    //xml方式的初始化方法
    public void myInit(){
        System.out.println("xml方式初始化");
    }

    @PostConstruct
    public void doPostConstruct(){
        System.out.println("注解的初始化方法");
    }

    
    
    public void sayHi(){
        System.out.println("执行 sayHi()");
    }

    @PreDestroy
    public void doPreDestroy(){
        System.out.println("do PreDestroy");
    }

}
import com.java.demo.component.BeanComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        BeanComponent beanComponent =
                context.getBean("beanComponent",BeanComponent.class);
        beanComponent.sayHi();
        context.destroy();
    }
}

打印:

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


你可能感兴趣的:(java,数据库,前端)