一、Bean 的作用域

在之前学习Java基础的时候,有接触到作用域这样的概念。一个变量并不一定在任何区域都是有效的,限定这个变量的可用性的代码范围就是该变量的作用域。

但是在这里 Bean 的作用域的概念和以前所认为的作用域有所不同。

Bean 的作用域是指 Bean 在 Spring 整个框架中的某种行为模式。

接下来,将会举一个案例来讲讲什么是作用域,什么是行为模式

案例概要:

创建一个共有的 Bean ,使用者A和使用者B都对该 Bean 进行了使用

使用者A在进行使用的时候,创建一个新的变量接收注入进来的 Bean,进行修改,将修改后的结果进行返回;

使用者B 直接将注入进来的 Bean 进行返回,不进行任何操作

代码实现:

步骤一:创建出一个公共的 Bean

@Component
public class UserComponent {
    @Bean
    public User getUser() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassWord("111111");
        return user;
    }
}

步骤二:使用者A获取到公共 Bean,进行修改

@Controller
public class UserControllerA {
    @Autowired
    private User user;
    public User getUser1() {
        System.out.println("使用者A拿到的原始user:"   user);
        User myUser = user;
        myUser.setName("李四");
        return myUser;
    }
}

步骤三:使用者B直接将获取到的公共的 Bean 进行返回

@Controller
public class UserControllerB {
    @Autowired
    private User user;
    public User getUser2() {
        return user;
    }
}

步骤四:main 中获取 UserControllerA 类和 UserControllerB 类使用查看

public class Start {
    public static void main(String[] args) {
        //获取 Spring 上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        //获取到Spring容器中的 UserControllerA 类(Bean 对象)
        UserControllerA userControllerA = context.getBean("userControllerA",UserControllerA.class);
        //使用 Bean 对象
        System.out.println("使用者A->" userControllerA.getUser1());
		//获取到Spring容器中的 UserControllerA 类(Bean 对象)
        UserControllerB userControllerB = context.getBean("userControllerB",UserControllerB.class);
        //使用 Bean 对象
        System.out.println("使用者B->" userControllerB.getUser2());
    }
}

预期结果:

使用者 A修改后,其结果是修改过的;使用者 B 没有修改过,其结果应该和原始user一样

结果显示:

和预期结果有所不同,使用者 A 和使用者 B 所得到的结果都是被修改过的。

这是因为在 Spring 中,Bean 默认情况下是单例状态,大家用的都是同一份对象,是全局共享的,当有其他人修改了该对象,另一个人所获取到的对象就是被修改过的,这便是 Bean 六大作用域之一——单例作用域(singleton)

在写 WEB 项目的时候,我们知道 DataSource 就是单例模式,使用单例,好处多多,可以确保所有对象都访问唯一实例,而且减少了内存的开支和系统性能的开销,因此 Bean 默认情况下是单例状态。

若想要按照预期结果输出,就需要将 Bean 的作用域设置成原型作用域,即无论谁来使用 Bean 对象,获取到的都是原始的 Bean 对象,大家各玩各的。

需要在注入的对象上使用注解修改作用域,有以下两种方法(Scope就是作用域的意思)

  • 直接将作用域以 String 类型写到()中
  • 使用全局参数,类似于枚举
@Component
public class UserComponent {
    //@Scope("prototype")    //方法一
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //方法二
    @Bean
    public User getUser() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setPassWord("111111");
        return user;
    }
}

Bean 的 6 种作用域

singleton:单例作用域

  • Bean 在 IoC 容器中只存在一个实例
  • 当 Bean 对象属性状态无需更新时使用该作用域
  • Spring 支持

prototype:原型作⽤域/多例作⽤域

  • 每次获取该 Bean 时都会创建新的实例,即获取的都是原始的 Bean
  • 当 Bean 对象属性状态会更新时使用该作用域
  • Spring 支持

request:请求作用域

  • 每次 HTTP 请求都会创建新的 Bean 实例
  • 一次 HTTP 请求和响应共享的 Bean
  • 限定 SpringMVC

session:会话作用域

  • 在一个 HTTP session中,创建一个 Bean 实例
  • 用户会话共享一个 Bean
  • 限定 SpringMVC

application:全局作用域

  • 在一个 HTTP Servlet Context中,创建一个 Bean 实例
  • 一个 WEB 上下文中共享一个 Bean
  • 限定 SpringMVC

websocket: HTTP WebSocket 作⽤域(不常用)

  • 在一个 HTTP WebSocket 中,创建一个 Bean 实例
  • 限定 Spring WebSocket

单例作用域和全局作用域比较像,但全局作用域范围没有单例作用域大,前者是 Spring 核心的作用域,后者是 Spring Web 中的作用域,前者作用于 IoC 容器,后者作用于 Servlet 容器

二、Spring 的执行流程

Spring 的执行流程也可以说是 Bean的执行流程,主要分成4部分

  • 启动 Spring 容器
  • 加载 XML 文件,实例化 Bean(进行内存的分配)
  • Bean 存到 Spring 容器中(五大类注解,方法注解)
  • 将存储的 Bean 中的注入的对象属性进行初始化,即进行装配(取出 Bean)

三、Bean 的生命周期

Bean 的生命周期即 Bean 从诞生到销毁的整个过程

实例化 Bean 对象,申请内存空间

设置 Bean 的属性,进行依赖注入和装配

Bean 的初始化

  • 各种 Aware 感知:BeanNameAware、BeanFactoryAware、ApplicationContextAware、…
  • 执⾏ BeanPostProcessor 初始化前置⽅法
  • 初始化方法:构造器方法 @PostConstructor (对象加载完依赖注入后执行)
  • 初始化方法:init-method
  • 执⾏ BeanPostProcessor 初始化后置⽅法

使用 Bean

销毁 Bean

  • 销毁方法:@PreDestroy
  • 接口方法:DisposableBean
  • 销毁方法:destroy-method

补充

实例化和初始化的区别

  • 实例化:这里的实例化和从前的实例化对象是有区别的,这里的实例化就负责内存的分配,一个从无到有的过程。实例化和属性设置时 Java 级别的系统“事件”,操作过程是不可人工干预的
  • 初始化:是对 Bean 进行填充的过程,程序员可以进行介入,真正的将 Bean 放到 Spring 容器中

@PostConstructor 和 @PreDestroy 是注解方式进行初始化和注销,init-method 和 destroy-method 是 XML 方法进行初始化和注销,一般只要使用其中的一种进行初始化

设置属性一定要在初始化之前,因为初始化也可能需要使用到注入的对象,如果没有进行属性的设置,初始化就会出现问题

案例:生命周期演示

@Component
public class BeanLife implements BeanNameAware {
    @Override
    public void setBeanName(String s) {
        System.out.println("BeanName 感知:"  s);
    }
    @PostConstruct
    public void postConstructor() {
        System.out.println("执行初始化方法:PostConstructor");
    }
    @PreDestroy
    public void preDestroy() {
        System.out.println("执行销毁方法:PreDestroy");
    }
    public void initMethod() {
        System.out.println("执行初始化方法:init-method");
    }
    public void destroyMethod() {
        System.out.println("执行销毁方法:destroy-method");
    }
}

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">
    <!-- 配置一下:bean注解扫描的根路径(方面后面更简单存储对象到spring容器)-->
    <content:component-scan base-package="com.bit.beans"></content:component-scan>
    <beans>
        <bean id="beanLife" class="com.bit.beans.Component.BeanLife" init-method="initMethod"
        destroy-method="destroyMethod"></bean>
    </beans>
</beans>

调用

public class Start {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new
                ClassPathXmlApplicationContext("spring.xml");
        BeanLife beanLife = context.getBean("beanLife",BeanLife.class);
        System.out.println("---使用 Bean 对象---");
        System.out.println("---注销 Bean 对象--- ");
        context.destroy();//容器的销毁相当于销毁所有的 Bean
    }
}

结果显示:

流程图展示:

到此这篇关于Java开发学习之Bean的作用域和生命周期详解的文章就介绍到这了,更多相关Bean作用域和生命周期内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Java开发学习之Bean的作用域和生命周期详解的更多相关文章

  1. ios – 不同作用域中相同命名常量的链接器错误

    我有一个名为“ID_KEY”的常量,它在3个单独的.m文件的顶部声明,其中没有包含其他文件.声明如下:而其他两个类也是如此.但是我收到一个链接器错误抱怨同名的多个定义.我的问题是为什么链接器抱怨这个呢?

  2. 15.6 Swift局部引用

    /**局部引用和全局引用1.作用域2.生命周期*/varref:Int=Int.init/**定义一个变量或者常量,如果不是可选类型的话,一定要有初始值。所谓的局部引用就是在代码块里面的引用就是局部引用。作用域生命周期都在该代码块中;离它最近的括号*/iftrue{varref:Student=Student.initref.name="ZHangsan"}//超出作用域啦//ref.name="ZHangsan"

  3. android – 在Jelly Bean平板电脑中隐藏系统栏(生根)

    我有一个AndroidJellyBean平板电脑已经扎根并且试图运行一个应用程序,其中包含隐藏系统栏的代码,但它没有被隐藏,任何人都可以帮助我解决这个问题.获取终端输出:结果包(00000000’….’)虽然我正在获得许可的祝酒:超级用户日志屏幕截图:解决方法当引入ICS时,systemUI类的进程ID从79更改为42.下面的代码适用于您的应用可能正在运行的任何Android版本.

  4. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  7. Java实现世界上最快的排序算法Timsort的示例代码

    Timsort 是一个混合、稳定的排序算法,简单来说就是归并排序和二分插入排序算法的混合体,号称世界上最好的排序算法。本文将详解Timsort算法是定义与实现,需要的可以参考一下

  8. Java日期工具类的封装详解

    在日常的开发中,我们难免会对日期格式化,对日期进行计算,对日期进行校验,为了避免重复写这些琐碎的逻辑,我这里封装了一个日期工具类,方便以后使用,直接复制代码到项目中即可使用,需要的可以参考一下

  9. Java设计模式之模板方法模式Template Method Pattern详解

    在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考虑今天的主角——模板方法模式

  10. Java 中 Class Path 和 Package的使用详解

    这篇文章主要介绍了Java 中 Class Path和Package的使用详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部