Bean 作用域和生命周期

这篇具有很好参考价值的文章主要介绍了Bean 作用域和生命周期。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Spring 容器是用来存储和读取 Bean 的 , 因此 Bean 是 Spring 中最核心的操作资源.

引入 Lombok

编写代码过程中 , bean 对象如果有多个属性 , 创建 Getter , Setter, 构造方法 等方法 , 会产生大量冗长的代码. 那么为了使代码更加简洁 , 我们可以使用 Lombok 框架 , 只需要一行注释 , 就可以避免大量冗长的代码. 需要注意的是,Lombok并不是Java语言的一部分,而是一个第三方库,需要在项目中引入Lombok的jar包才能使用。同时,由于Lombok是通过注解来实现代码生成的,因此在使用Lombok时需要确保IDE和编译器支持注解处理。

Maven 中复制 lombok 依赖

Bean 作用域和生命周期

pom.xml 插入 lombok 依赖

Bean 作用域和生命周期

代码示例:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private int age;
    private String email;
}

在这个示例中,我们使用了Lombok的@Data、@NoArgsConstructor和@AllArgsConstructor注解。

@Data注解可以自动生成getter、setter、equals、hashCode和toString等方法,省去了手动编写这些方法的麻烦。

@NoArgsConstructor注解可以自动生成无参构造函数,方便我们在创建对象时使用。

@AllArgsConstructor注解可以自动生成全参构造函数,方便我们在创建对象时同时设置对象的属性值。


1. Bean 的作用域问题

假设有一个公共的 Bean , 提供给用户 A 和 用户 B 使用 , 如果 A 修改了 Bean 的公共数据 , 导致 B 在使用时发生与预期不符的错误.

创建一个实体类

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

存储 User 对象

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

UserController 修改 Bean 的公共数据:

@Controller
public class UserController {
    @Autowired
    private User user;

    public void sayHi(){
        System.out.println(user);
        //修改 User
        User myUser = user;
        myUser.setName("张三");
        System.out.println("myUser->" + myUser.getName());
    }
}

UserController2 访问 Bean 中的公共数据:

@Controller
public class UserController2 {
    @Resource
    private User user;

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

启动类中调用:

public class App {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        UserController userController = context.getBean("userController", UserController.class);
        userController.sayHi();
        UserController2 userController2 = context.getBean("userController2", UserController2.class);
        userController2.sayHi2();
    }
}

结果发现公共数据被修改:

Bean 作用域和生命周期

出现上述问题的原因是 , Bean 默认状态下是单例模式 , 即所有人使用的都是同一个对象 , 那么当多个用户并发执行时 , 一定会篡改公共数据.


2. 作用域定义

2.1 作用域类型

1. singleton(单例作用域)

  • 描述: 由于 Spring 框架除了追求高效还追求性能 , 因此使用单例模式作为默认作用域. 该作用域下的 Bean 在整个 IoC容器中只存在一份 , 无论是获取还是注入都是同一个对象.
  • 场景: 通常无状态的 Bean 使用该作用域. (无状态指对象的属性无需更新)

2. prototype(原型作用域)

  • 描述: 在该作用域下 , 每次 Bean 的请求都会创建新的实例.
  • 场景: 通常有状态的 Bean 使用该作用域.

3. request(请求作用域)

  • 描述: 每次 Http 请求都会创建一个 Bean 对象.
  • 场景: 一次 Http 请求和响应共享的 Bean 对象 , 适用于 Spring MVC 项目

4. session(会话作用域)

  • 描述: 一次 Http session 中 , 定义一个 Bean 对象 , 适用于 Spring MVC项目
  • 场景: 每次 Session 会话共享一个 Bean 对象.

5. application(全局作用域)

  • 描述: 一个 Http Servlet context 中共享一个 Bean
  • Web 应用的上下文 , Spring MVC.

**6. websocket(Http WebSocket 作用域) **

  • 描述: 在一个 Http WebSocket 生命周期中 , 定义一个 Bean对象.
  • 场景: 只适用于 Spring WebSocket 项目

总结:

  • 我们目前使用的是 Spring core 项目 , 因此只能使用 singleton 和 prototype 作用域.
  • singleton 作用于 IoC 容器 , application 作用域 Servlet 容器.

2.2 Bean 作用域的设置

我们可以在存储Bean对象的时候通过 @Scope 注解设置作用域.

代码示例:

我们可以通过两种方式设置作用域:

  • 直接使用 prototype 设置作用域

存储 Bean 时设置作用域:

@Component
public class UserBeans {
    @Bean
    @Scope("prototype")
    public User user(){
        //伪代码
        User user = new User();
        user.setName("王五");
        user.setId(10);
        return user;
    }
}

注入时会创建新对象:

@Controller
public class UserController {
    @Autowired
    private User user;
}

再次运行, 结果与预期一致.

Bean 作用域和生命周期

  • 使用 @ Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

为什么使用这么麻烦的方式 , 因为有自动提示 , 可以防止单词拼错 以及 使用不合法的作用域.

@Component
public class UserBeans {
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public User user(){
        //伪代码
        User user = new User();
        user.setName("王五");
        user.setId(10);
        return user;
    }
}

3. Bean 的生命周期

所谓 Bean 的生命周期就是 Bean 从创建到销毁的过程.

3.1 执行流程:

大致流程分为以下五步:

1.实例化 Bean (为Bean 分配内存空间)

当 Spring 容器加载配置文件时 , 会根据其中注册的 Bean 利用反射机制 Bean 实例.

2.设置属性(Bean 对象的注入和装配)

Bean 实例化之后, Spring 容器会自动将配置文件中 , 定义的属性值注入到 Bean 实例中(包括基本类型, 对象, 集合).

3.Bean 初始化

  • 实现了各种 Aware 通知的方法 , 如 BeanNameAware , BeanFactoryAware , ApplicationContextAware等.
  • 初始化前置方法: Spring执行所有实现了BeanPostProcessor接口的类的postProcessBeforeInitialization()方法,这些类可以在bean初始化之前进行一些自定义的处理。
  • 执行初始化方法: (有两种) 1.注解方式: @PostConstruct , 2.xml 方式: init-method方法. 如果bean实现了InitializingBean接口,Spring将调用其afterPropertiesSet()方法
  • 初始化后置方法: Spring执行所有实现了BeanPostProcessor接口的类的postProcessAfterInitialization()方法,这些类可以在bean初始化之后进行一些自定义的处理

4.使用 Bean

5.销毁 Bean 对象

  • 常用方法: 如 @PreDestroy , DisposableBean 接口方法

Bean 作用域和生命周期

例如: 将买房子视为 Bean 的生命周期

  1. 买一个房子 , 相当于实例化 Bean 开辟内存空间
  2. 装修房子 , 相当于配置文件给 Bean 注入各种属性
  3. 买家具 , 相当于初始化 Bean
  4. 住房 , 相当于使用 Bean
  5. 将房子卖出 , 相当于销毁 Bean

由此也可以得出 , 配置文件给 Bean 注入属性 , 必须排在初始化之前 , 因为初始化可能调用属性.(装修完才能安家具)

3.2 代码示例:

PostConstruct 版

@Component
public class UserBeans implements BeanNameAware {
    @PostConstruct
    public void PostConstruct(){
        System.out.println("执行了 PostConstruct");
    }
    @PreDestroy
    public void PreDestroy(){
        System.out.println("执行了 PreDestroy");
    }
    @Override
    public void setBeanName(String s) {
        System.out.println("执行了 setName" + s);
    }
}

xml 版

我们可以在配置文件中设置各种属性.

Bean 作用域和生命周期

@Component
public class BeanComponent implements BeanNameAware {

    @Override
    public void setBeanName(String s) {
        System.out.println("执行了通知 BeanName ->" + s);
    }
    //xml 方式的初始化方法
    public void myInit(){
        System.out.println("XML 方式初始化");
    }
    public void sayHi(){
        System.out.println("执行 sayHi");
    }
   //xml 方式的销毁
    public void preDestroy(){
        System.out.println("执行了销毁方法");
    }
}

调用启动类:

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        BeanComponent component = context.getBean("beanComponent" , BeanComponent.class);
        component.sayHi();
        context.destroy();
    }
}

结果与预期一致:

Bean 作用域和生命周期

4.Spring 生命周期

Spring执行流程如下:

  1. 应用程序启动时,Spring容器被创建。
  2. Spring容器读取并解析配置文件,将其中的bean定义加载到内存中。
  3. Spring容器使用Java反射机制创建bean实例。
  4. Spring容器将配置文件中指定的属性值或引用注入到bean实例中。
  5. 如果bean实现了InitializingBean接口,Spring容器将调用其afterPropertiesSet()方法。如果在配置文件中指定了init-method属性,则Spring容器将调用该方法。
  6. 如果bean实现了BeanPostProcessor接口,Spring容器将执行其postProcessBeforeInitialization()方法,进行一些自定义的处理。
  7. Spring容器将bean实例化后,将其放入容器中管理。
  8. 应用程序向Spring容器请求一个bean,Spring容器根据请求的名称或类型,从容器中返回一个bean实例。
  9. 如果bean实现了BeanPostProcessor接口,Spring容器将执行其postProcessAfterInitialization()方法,进行一些自定义的处理。
  10. 应用程序使用bean实例完成相应的业务逻辑。
  11. 应用程序关闭时,Spring容器将销毁所有的bean实例。
  12. 如果bean实现了DisposableBean接口,Spring容器将调用其destroy()方法。如果在配置文件中指定了destroy-method属性,则Spring容器将调用该方法。

需要注意的是,Spring执行流程中的每一步都可以进行自定义的配置和处理,以满足不同的业务需求
用程序向Spring容器请求一个bean,Spring容器根据请求的名称或类型,从容器中返回一个bean实例。文章来源地址https://www.toymoban.com/news/detail-449116.html

到了这里,关于Bean 作用域和生命周期的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 5、Spring之bean的作用域和生命周期

    5.1.1.1、配置bean 注意:当bean不配置scope属性时,默认是singleton(单例) 5.1.1.2、测试 由控制台日志可知,此时ioc获取到的两个bean本质上是同一个对象 5.1.2.1、配置bean 5.1.2.2、测试 由控制台日志可知,此时ioc获取到的两个bean本质上是不同的对象 如果是在WebApplicationContext环境下

    2024年02月14日
    浏览(45)
  • Spring系列4 -- Bean的作用域和生命周期

    目录 1. 案例 2. 作用域定义 2.1 Bean的6种作用域 2.2 设置作用域 3. Sring的执行流程 4. Bean的生命周期 思考: 为什么不是先进行初始化然后再进行设置属性呢?         假设现在有⼀个公共的 Bean,提供给 A ⽤户和 B ⽤户使⽤,然⽽在使⽤的途中 A ⽤户却“悄悄”地修改了公共

    2024年02月15日
    浏览(33)
  • 【Spring学习】Bean对象的作用域和生命周期,了解了这些你就真正熟悉spring框架了.

    前言: 大家好,我是 良辰丫 ,我们已经学会了Spring的存取,今天我们将一起来学习Bean对象的作用域和生命周期.💌💌💌 🧑个人主页:良辰针不戳 📖所属专栏:javaEE进阶篇之框架学习 🍎励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。 💦期

    2024年02月07日
    浏览(62)
  • @Autowired和@Resource注解之间的关系区别,Bean的作用域和生命周期,Spring的执行流程

    目录 一. @Autowired 和 @Resource 注解 二. Bean的作用域  1. singleton(单例模式) 2. prototype(原型模式)(多例模式) 3. 请求作用域:request 4. 会话作用域:session 三. Spring 的执行流程 四. Bean 的生命周期   1. 实例化  2. 设置属性  3. Bean 初始化      3.1 执行各种各种 Aware 通知;     

    2024年02月04日
    浏览(63)
  • Bean 作用域和生命周期

    Spring 容器是用来存储和读取 Bean 的 , 因此 Bean 是 Spring 中最核心的操作资源. 编写代码过程中 , bean 对象如果有多个属性 , 创建 Getter , Setter, 构造方法 等方法 , 会产生大量冗长的代码. 那么为了使代码更加简洁 , 我们可以使用 Lombok 框架 , 只需要一行注释 , 就可以避免大量冗长

    2024年02月05日
    浏览(78)
  • Bean作用域和生命周期

    hi,今天为大家带啦Bean的作用域和生命周期的相关知识 Bean的作用域和我们之前学过的不一样,我们之前学的作用域是一个范围,而现在指的是 Bean在Spring框架中的某种行为模式,也就是一个动作. 这样干巴巴的说看我可能无法理解,我们来举个例子 创建一个公共类的一个公共对象

    2024年02月15日
    浏览(52)
  • Bean的作用域和生命周期

    目录 1.作⽤域定义 1.1Bean的6个作用域 1.singleton:单例作用域 2.prototype:多例作用域 3.request:请求作用域 4.session:会话作用域 5.application:全局作用域 6.websocket:HTTP WebSocket作用域 单例作⽤域(singleton) VS 全局作⽤域(application) 1.2设置作用域 1.直接设置值@Scope(\\\"potptype\\\") 2.用枚举设置:@Scop

    2024年02月02日
    浏览(88)
  • 【JavaEE进阶】Bean 作用域和生命周期

    注意在此例子中需要用到lombok lombok是什么? Lombok 是一个 Java 库,它通过注解的方式来简化 Java 代码的编写。它提供了一组注解,让我们可以通过在代码中添加这些注解来自动生成样板式的代码,如 getter、setter、构造函数、toString 等。 使用 Lombok 可以有效地减少冗余的样板代

    2024年02月12日
    浏览(48)
  • Spring Bean作用域与生命周期

    目录 Bean的作用域: Bean有六大行为模式 1、singleton:单例模式(默认) 2、prototype: 原型模式(多例模式) 3、request: 请求作用域(Spring MVC) 4、session: 会话作用域(Spring MVC) 5、application: 全局作用域(Spring MVC) 6、websocket: HTTP WebSocket 作用域(Spring WebSocket) applicationContext和singleton的区别  Bea

    2024年02月02日
    浏览(42)
  • 【Spring】Bean的作用域与生命周期详情:请简述Spring的执行流程并分析Bean的生命周期?

     我们都知道,Spring框架为开发人员提供了很多便捷,这使得开发人员能够更加专注于应用程序的核心业务逻辑,而不需要花费大量时间和精力在技术细节上。作为一个包含众多工具方法的IoC容器,存取JavaBean是其极为重要的一个环节。本文就对Spring中的Bean的作用域和生命周

    2024年02月12日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包