文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java开发学习之Bean的作用域和生命周期详解

2024-04-02 19:55

关注

一、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就是作用域的意思)

@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:单例作用域

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

request:请求作用域

session:会话作用域

application:全局作用域

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

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

二、Spring 的执行流程

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

三、Bean 的生命周期

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

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

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

Bean 的初始化

使用 Bean

销毁 Bean

补充

实例化和初始化的区别

@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作用域和生命周期内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯