JavaEE高阶---Bean 作用域和生命周期

一 : Bean的默认作用域

Bean 默认情况下是单例状态(singleton),所有人使用的都是同一个对象.

举例理解Bean的单例状态 :

假设现在有一个公共的 Bean,提供给 A 用户和 B 用户使用,然而在使用的途中 A 用户却“悄悄”地修改了公共 Bean 的数据,导致 B 用户在使用时发生了预期之外的逻辑错误 .

假设现在有一个IkunBean , 张三和李四和都要使用这个IkunBean .

Ikun.java

package  Ikun;

public class Ikun {
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

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


IkunBean

package com;

import Ikun.Ikun;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class IkunBean {

    @Bean
    public Ikun chicken() {
        Ikun ikun = new Ikun();
        ikun.setAge(26);
        ikun.setName("鲲鲲");
        return ikun;
    }
}


Controller1.java

package com;

import Ikun.Ikun;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * 张三取出Bean对象
 */

@Controller
public class Controller1 {

    @Autowired
    private Ikun ikun;

    public void docontroller1() {
        System.out.println("张三取出该对象");
        System.out.println("原数据:"+ ikun);

        Ikun ikun1 = ikun;
        ikun1.setName("只因");
        System.out.println("现数据:"+ ikun1);
    }
}


Controller2.java

package com;

import Ikun.Ikun;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * 李四取出Bean对象
 */

@Controller
public class Controller2 {

    @Autowired
    private Ikun ikun;

    public void doController2() {
        System.out.println("李四取出该对象");
        System.out.println(ikun);
    }
}

JavaEE高阶---Bean 作用域和生命周期_第1张图片

分析 :

JavaEE高阶---Bean 作用域和生命周期_第2张图片

总结 :

Bean作用域定义 : Bean对象在整个Spring中的某种行为模式 . 比如单例作用域表示的是Bean对象在Spring(框架)中只有一份 .

二 : 作用域定义

  1. 变量的作用域 : 限定程序中变量的可用范围叫做作用域,或者说在源代码中定义变量的某个区域就叫做作用域.
  2. Bean的作用域: 指 Bean 在 Spring 整个框架中的某种行为模式,比如 singleton 单例作用域,就表示 Bean 在整个 Spring 中只有一份,它是全局共享的,当其他人修改了这个值之后,另一个人读取到的就是被修改的值 .

三 : Bean的六种作用域及其说明

JavaEE高阶---Bean 作用域和生命周期_第3张图片

3.1 singleton

  • 官方说明:(Default) Scopes a single bean definition to a single object instance for each Spring IoC container .
  • 描述:该作用域下的Bean在IoC容器中只存在一个实例:获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是同一个对象 .
  • 场景:通常无状态的Bean使用该作用域。无状态表示Bean对象的属性状态不需要更新 .
  • 备注:Spring默认选择该作用域 .

3.2 prototype

  • 官方说明:Scopes a single bean definition to any number of object instances .
  • 描述:每次对该作用域下的Bean的请求都会创建新的实例:获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是新的对象实例 .
  • 场景:通常有状态的Bean使用该作用域 , 有状态表示Bean对象的属性状态需要频繁更新 .

3.3 request

  • 官方说明:Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:每次http请求会创建新的Bean实例,类似于prototype
  • 场景:一次http的请求和响应的共享Bean
  • 备注:限定SpringMVC中使用

3.4 Session

  • 官方 说明:Scopes a single bean definition to the lifecycle of an HTTP Session.Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:在一个http session中,定义一个Bean实例
  • 场景 : 用户回话的共享Bean, 如:记录某个用户的登陆信息
  • 备注:限定SpringMVC中使用

3.5 application

  • 官方说明:Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:在一个http servlet Context中,定义一个Bean实例
  • 场景:Web应用的上下文信息, 如:记录一个应用的共享信息
  • 备注:限定SpringMVC中使用

3.6 websocket

  • 官方说明:Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:在一个HTTP WebSocket的生命周期中,定义一个Bean实例
  • 场景:WebSocket的每次会话中,保存了一个Map结构的头信息,将用来包裹客户端消息头。第一次初始化后,直到WebSocket结束都是同一个Bean。
  • 备注:限定Spring WebSocket中使用 . [注意 : Spring MVC 模式下也可以使用websocket]
  • 参考文章 : java WebSocket开发入门WebSocket

仍然是前面的例子 , 此处我们将Bean的作用域设置为多例模式 , 查看运行效果 . 设置多例模式的方法有以下两种 :

JavaEE高阶---Bean 作用域和生命周期_第4张图片
运行结果 :

JavaEE高阶---Bean 作用域和生命周期_第5张图片

四 : Spring执行流程

JavaEE高阶---Bean 作用域和生命周期_第6张图片

五 : Bean的生命周期

JavaEE高阶---Bean 作用域和生命周期_第7张图片

BeanComponent.java

package com.component;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * 演示Bean的生命周期
 */

@Component
public class BeanComponent implements BeanNameAware {

    //依赖注入
    @Autowired
    private UserComponent userComponent;

    public BeanComponent(UserComponent userComponent) {
        this.userComponent = userComponent;
        userComponent.doComponent();
        System.out.println("执行BeanComponent的构造方法!");
    }
    
    //继承 BeanNameAware接口,执行通知方法
    public void setBeanName(String s) {
        System.out.println("执行了setBeanName通知 : " + s);
    }
    
    //xml中init-method指定的方法
    public void initMethod() {
        System.out.println("执行了initMethod方法!");
    }

    
    @PostConstruct
    public void myPostConstruct() {
        System.out.println("执行了PostConstruct方法!");
    }


    //销毁前执行方法
    @PreDestroy
    public void myPreDestroy() {
        System.out.println("执行了PreDestroy方法!");
    }


    //使用Bean
    public void use() {
        System.out.println("执行了use方法!");
    }
}

Test5.java

import com.component.BeanComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Bean的生命周期
 */
public class Test5 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        BeanComponent component = (BeanComponent) context.getBean("beanComponent");
        component.use();
        context.destroy();
    }
}

spring-config.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"></content:component-scan>
    <bean id="beanComponent" class="com.component.BeanComponent"
          init-method="initMethod"></bean>
</beans>



解释 :

JavaEE高阶---Bean 作用域和生命周期_第8张图片

JavaEE高阶---Bean 作用域和生命周期_第9张图片

Bean的生命周期类似于买房的过程 :

  1. 先买房(实例化 , 从无到有) ;
  2. 装修(设置属性) ;
  3. 买家电 (各种初始化) ;
  4. 入住(使用Bean) ;
  5. 卖出去(Bean销毁) .

Q : 为什么要先设置属性(依赖注入)再初始化呢 ?

A : 防止初始化时要用到依赖注入的对象 .

重点 : 掌握Bean的大的执行流程 .

JavaEE高阶---Bean 作用域和生命周期_第10张图片

你可能感兴趣的:(JavaEE高阶,java,jvm,spring)