Spring初识(四)

文章目录

  • 前言
  • 一.Bean的作用域
    • 1.1 作用域例子
    • 1.2 Bean的作用域类型
  • 二.Bean的生命周期

前言

在前面我们学习了spring简单的读取和存储对象之后,Spring 中 Bean 是最核心的操作资源,我们接下来会介绍Bean对象.

一.Bean的作用域

什么是Bean作用域呢?
限定程序中变量的可用范围叫做作用域,或者说在源代码中定义变量的某个区域就叫做作用域。
而Bean 的作用域是指Bean 在 Spring整个框架中的某种行为模式.
我们具体用一个例子来说Bean的域.例子如下:

1.1 作用域例子

具体的场景如下:
假设现在有一个公共的Bean,提供给A用户和B用户使用,然而在使用的途中A用户却“悄悄"地修改了公共 Bean 的数据,导致B用户在使用时发生了预期之外的逻辑错误。
具体先看代码:
1.准备好具体的User类

public class User {
    private int id;
    private String name;

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

2.把User存入spring容器中

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

3.这里有两个对象,分别对User对象做操作

对象一.

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

}

对象二:

@Controller
public class UserController2 {
    @Resource
    private User user;
    public void printUser2(){
        System.out.println("user->"  +user);
    }
}

4.具体的操作

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

    }
}

执行结果:
Spring初识(四)_第1张图片

其实这里的预期结果,我们第二次读取的操作的时候,应该打印的还是关羽的信息,但是现在出现了,张飞.按照正常的执行流程,我们应该出现的是关羽的信息.
这就是因为Bean对象是有作用域的.下面介绍Bean的作用域

1.2 Bean的作用域类型

在Spring中,Bean的作用域类型决定了Bean的生命周期和在应用程序中的可见性。Spring框架支持以下几种常见的Bean作用域类型:

  1. Singleton(默认): 在整个应用程序中,只创建一个Bean实例。无论多少次请求该Bean,都返回同一个实例。这是Spring默认的作用域。可以通过@Scope(“singleton”)或者不添加@Scope注解来指定Singleton作用域。

  2. Prototype: 每次请求Bean时,都会创建一个新的实例。每次获取Bean时,都会返回一个不同的实例。可以通过@Scope(“prototype”)来指定Prototype作用域。

  3. Request: 每次HTTP请求都会创建一个新的Bean实例。在同一个请求中,多次获取Bean时都会返回同一个实例。通常用于Web应用程序中的每个请求,保证在同一个请求中的多次调用中都使用同一个Bean实例。可以通过@Scope(“request”)来指定Request作用域。

  4. Session: 每个HTTP Session都会创建一个新的Bean实例。在同一个Session中,多次获取Bean时都会返回同一个实例。通常用于Web应用程序中,保证在同一个Session中的多次调用中都使用同一个Bean实例。可以通过@Scope(“session”)来指定Session作用域。

  5. Application(仅适用于Web应用): 在整个Web应用中,只创建一个Bean实例。无论多少次请求该Bean,都返回同一个实例。通常用于Web应用程序中,保证在整个应用中都使用同一个Bean实例。可以通过@Scope(“application”)来指定Application作用域。

  6. WebSocket是一种在Web浏览器和服务器之间进行全双工通信的协议,允许实时、双向的数据传输。WebSocket的作用域主要涉及在Web应用程序中与其他部分的通信范围。

因此知道了这些作用域之后,我们回到上面的案例,我们要怎么才能达到我们的预期效果呢.
@Scope标签既可以修饰方法也可以修饰类,@Scope有两种设置方式:
1.直接设置值:@Scope(“prototype”)
2.使用枚举设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
代码如下:

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

执行结果:
Spring初识(四)_第2张图片

最后我们来做一个简单的总结

1.单例模式: singleton(默认模式)>性能的考虑2.原型模式: prototype
3.请求作用域: request,每次 HTTP请求,都会创建一个Bean 对象。【适用于Spring MVC/Spring Web】4.会话作用域: session,每次Session会话共亨一个 Bean。【Spring MVC】
5.全局作用域: appli cation,一个http servlet context中共享一个bean。【Spring MVC】6.webscoket:网络长连接,只适用于Spring WebSocket项日。

二.Bean的生命周期

Bean的生命周期主要包括以下几个阶段:

  1. 开辟内存空间:实例化≠初始化
  2. 设置属性(注入属性)
  3. 初始化
    3.1各种通知
    3.2初始化前置方法
    3.3 初始化方法【两种实现方式: xml 方式、注解方式】
    3.4 初始化后置方法
  4. 使用Bean
  5. 销毁Bean 对象

让我们以一个生活中的例子来演示这样的流程:购买一台新的电视。

  1. 开辟内存空间(实例化): 当你购买一台新的电视时,实际上是在商店里买到了一台特定型号的电视,这时候可以认为你在购买电视的过程中已经开辟了一块内存空间,这个空间对应于新的电视对象。

  2. 设置属性(注入属性): 购买电视后,你将其搬回家并连接到电源和其他设备(例如DVD播放器、游戏机等),这个过程类似于将电视的属性值进行设置和注入。

  3. 初始化:

    各种通知: 开启电视后,它可能会显示欢迎信息或品牌标志,这是一种初始化阶段的通知。
    初始化前置方法: 在使用电视之前,你可能需要对电视进行一些设置,如调整屏幕亮度、音量等,这可以看作是初始化前置方法。
    初始化方法【两种实现方式:xml方式、注解方式】: 电视可以具有不同型号和功能,而对应于不同型号和功能,它们可能需要在初始化阶段进行不同的操作。例如,一些电视型号可能需要连接网络、搜索频道,这些可以通过在电视对象上调用初始化方法来实现。在Spring中,初始化方法可以通过在Bean定义中使用init-method属性或在Bean类上使用@PostConstruct注解来指定。
    初始化后置方法: 在初始化阶段完成后,电视可以显示出预设频道或导航界面,这可以看作是初始化后置方法。

  4. 使用电视(使用Bean): 一旦电视初始化完成并连接好,你可以开始使用它来观看电视节目、播放DVD或玩游戏,这是电视被使用的阶段。

  5. 销毁电视(销毁Bean对象): 长期使用后,如果你决定不再使用这台电视,或者它出现了故障,你可能会将其处理掉或退还给商店。这个过程类似于销毁Bean对象,在Spring中,销毁Bean对象可以通过在Bean定义中使用destroy-method属性或在Bean类上使用@PreDestroy注解来指定。

综上所述,购买一台新的电视可以类比为Bean的生命周期。在整个过程中,我们可以类比内存空间的开辟(实例化)、设置电视的属性(注入属性)、电视的初始化阶段(包括各种通知、初始化前置方法、初始化方法和初始化后置方法)、使用电视(使用Bean)、销毁电视(销毁Bean对象)等。

然后用一个代码的例子说明:
代码如下:

package com.java.demo.component;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanPostProcessor;

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

public class BeanCompont implements BeanNameAware, BeanPostProcessor {
    @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");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("do postProcessBeforeInitialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("do postProcessAfterInitialization");
        return bean;
    }
}

具体执行:

   ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        BeanCompont compont = context.getBean("beanCompont", BeanCompont.class);
        compont.sayHi();
        context.destroy();

执行结果:
Spring初识(四)_第3张图片

你可能感兴趣的:(javaEE进阶,spring,java,后端)