Java Spring原理之Bean的作用域、Bean的生命周期及Spring自动配置详解

 更新时间:2025年11月26日 08:28:34   作者:英雄不问出处~  
Spring是一个非常流行的Java应用程序框架,它提供了一个灵活的机制来管理Bean的生命周期和作用域,这篇文章主要介绍了Java Spring原理之Bean的作用域、Bean的生命周期及Spring自动配置的相关资料,需要的朋友可以参考下

Spring原理

Bean的作用域

  1. 概念:从Context中获取对象,得到的都是同一个,这种行为模式,就称为bean的作用域
    多次获取,拿到的Bean的对象都是同一个

  2. 在Spring中支持6种作用域,后4种在Spring MVC环境才生效
    (1) singleton:单例作用域
    每个Spring IoC容器内同名称的bean只有一个实例(单例)(默认)
    (2) prototype:原型作用域(多例作用域)
    每次使用该bean时会创建新的实例(非单例)
    (3) request:请求作用域
    每个HTTP 请求生命周期内, 创建新的实例(web环境中, 了解)
    (4) session:会话作用域
    每个HTTP Session生命周期内, 创建新的实例(web环境中, 了解)
    (5) Application: 全局作用域
    每个ServletContext生命周期内, 创建新的实例(web环境中, 了解)
    (6) websocket:HTTP WebSocket 作用域
    每个WebSocket生命周期内, 创建新的实例(web环境中,了解)

验证是单例的

  1. 从context中获取对象
  2. 属性注入获取对象
@Configuration
public class BeanConfig {
    @Bean
    public User user1(){
        return new User(1,"zhangsan");
    }

    // 声明作用的范围(声明了一个单例的作用域)
    // 声明了一个单例的对象
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    // @Scope("singleton")
    @Bean
    public User singleUser(){
        return new User();
    }
}

    // 有多个@Autowired的时候,指定名称使用哪个
    @Resource(name = "singleUser")
    private User singleUser;
    
@RequestMapping("scope")
@RestController
public class BeanScopeController {
    @Autowired
    private ConfigurableApplicationContext context;

    // 有多个@Autowired的时候,指定名称使用哪个
    @Resource(name = "singleUser")
    private User singleUser;

    @RequestMapping("/single")
    public String single(){
         // 1. 从context中获取对象
        String user = (String) context.getBean("singleUser");
        // 2. 属性注入获取对象

        return "从context中获取的对象 " + System.identityHashCode(user)
                + "属性注入获取的对象" + System.identityHashCode(singleUser);
    }
}
  1. 结果展示:可以看出他们获取的是同一个对象

多例的作用域

  1. 多例模式(原型模式)
    属性注入在程序启动的时候会创建一个对象,之后再重新启动,才会改变

context获取的对象,每次重新启动都会重新获取对象,因此每次对象都会发生变化

  //对象
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public User prototypeUser(){
        return new User();
    }

 // 注解
@Resource(name = "prototypeUser")
    private User prototypeUser;

@RequestMapping("/phototype")
    public String phototype(){
        // 1. 从context中获取对象
        User user = (User) context.getBean("prototypeUser");
        // 2. 属性注入获取对象

        return "从context中获取的对象 " + System.identityHashCode(user)
                + "属性注入获取的对象" + System.identityHashCode(prototypeUser);
    }
  1. 展示效果:每次刷新,拿到的不是同一个对象,每次请求都会生成一个新的对象

  2. 出现的问题:没有验证成功的原因是我们写的是同一个User对象,@Data中的hashcode()会根据id判断他们是否是同一个对象,**这里的new User()都是同一个对象,那么这里就判断了他们是同一个对象,Spring进行了优化,**因此每次request刷新都不变,理论上每次刷新,都会创建一个新的对象,每次都会变化
    这里就要使用jdk,自带的toString()方法,jdk有hashcode()方法,用自带的toString()方法,它每次new都会生成不同的对象,因此可以看出request,每次都是变化的了
    所以这里不同@Data,而用@Getter和@Setter

对上面问题的再一次解释:
Spring使用了代理模式,所以代理的User,每次都是同一个

Spring中才有代理模式:

request的作用域

  1. @RequestScope等同于@Scope,这两者含义是一样的

  2. 虽然是同一个对象,但是每次请求都会重新创建对象

// request的作用域
@RequestScope
    @Bean
    public User requestUser(){
        return new User();
    }


// 注解的方式
@Resource(name = "requestUser")
    private User requestUser;

@RequestMapping("/request")
    public String request(){
        // 1. 从context中获取对象
        User user = (User) context.getBean("requestUser");
        // 2. 属性注入获取对象

        return "从context中获取的对象 " + System.identityHashCode(user)
                + "属性注入获取的对象" + System.identityHashCode(requestUser);
    }

session的作用域

  1. 在不同的浏览器下,是不同的会话,自然会出现不同的地址
@SessionScope
    @Bean
    public User sessionUser(){
        return new User();
    }
@Resource(name = "sessionUser")
    private User sessionUser;

@RequestMapping("/session")
    public String session(){
        // 1. 从context中获取对象
        User user = (User) context.getBean("sessionUser");
        // 2. 属性注入获取对象

        return "从context中获取的对象 " + System.identityHashCode(user)
                + "属性注入获取的对象" + System.identityHashCode(sessionUser);
    }
  1. 效果展示:
    如果是同一个浏览器,并且没有清除cookie,那么session不会发生变化

    如果是不同的浏览器,就是不同的cookie,session自然会发生变化

application的作用域

  1. application的作用域:在整个应用中都是同一个的,和我们的单例一样,在同一个应用中都是同一个

  2. 两者的区别:一个web容器中(一个tomcat中),可以部署多个服务(多个ApplicationContext),而一个Web容器中有多个ServletContext - 每个Web应用都有自己独立的ServletContext实例

一个tomcat可以启动多个web服务

@ApplicationScope
    @Bean("applicationUser")// 指定名字
    public User applicationUser(){
        return new User();
    }

// 注解注入
@Resource(name = "applicationUser")
    private User applicationUser;

@RequestMapping("/application")
    public String application(){
        // 1. 从context中获取对象
        User user = (User) context.getBean("applicationUser");
        // 2. 属性注入获取对象

        return "从context中获取的对象 " + user
                + "属性注入获取的对象" + applicationUser;
    }
  1. 在不同的浏览器中,进行展示,都是同一个

Bean的生命周期

代码的使用

  1. 对象的生命周期:生命周期指的是一个对象从诞生到销毁的整个生命过程, 我们把这个过程就叫做一个对象的生命周期。

Bean 的生命周期分为以下5个部分:
2. 实例化(为Bean分配内存空间)
3. 属性赋值(Bean注入和装配, 比如 @AutoWired )
4. 初始化
a. 执行各种通知, 如 BeanNameAware , BeanFactoryAware ,
ApplicationContextAware 的接口方法.
b. 执行初始化方法
▪ xml定义 init-method
▪ 使用注解的方式 @PostConstruct
▪ 执行初始化后置方法( BeanPostProcessor )
5. 使用Bean
6. 销毁Bean
a. 销毁容器的各种方法, 如 @PreDestroy , DisposableBean 接口方法, destroy-
method

举个例子:

2. 写一个案例,来验证Bean的生命周期

// BeanLifeComponent
@Component
public class BeanLifeComponent {
    private User user;
    // 构造
    public BeanLifeComponent() {
        System.out.println("执行构造方法~");
    }

    // 属性注入
    // 指定注入的对象
    // 表示注入的user1对象
    @Qualifier("user1")
    @Autowired
    public void setUser1(User user) {
        this.user = user;
        System.out.println("属性注入~");
    }

    // 初始化
    // 使用@PostConstruct实现初始化
    @PostConstruct // 这个用的比较多
    public void init(){
        System.out.println("执行初始化方法~");
    }

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

    // 销毁
    // 基本上不会用
    @PreDestroy // pre表示 bean 销毁前执行,销毁的时候就直接清理对象了
    public void destroy(){
        System.out.println("执行destroy销毁方法~");
    }
}

// 测试方法
public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringConfigApplication.class, args);
        BeanLifeComponent lifeComponent = context.getBean(BeanLifeComponent.class);
        lifeComponent.use();
        // 有不手动点击结束进程的方式来执行destroy方法
        // ((AbstractApplicationContext)context).destroy();
   }

展示效果:

手动关闭进程:

源码阅读

了解生命周期的分类

  1. bean的实例化,属性注入,bean的初始化

2. 执行各种通知,这些通知都是在初始化方法之前执行,属性注入之后执行的

SpringBoot自动配置

  1. 这些注解的底层就是Spring自动配置的

  2. 元注解:是注解其他注解的注解

有选择地导入配置类

总结

到此这篇关于Java Spring原理之Bean的作用域、Bean的生命周期及Spring自动配置的文章就介绍到这了,更多相关Java Spring原理详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java后端访问https证书的问题及解决

    java后端访问https证书的问题及解决

    这篇文章主要介绍了java后端访问https证书的问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • java求最大公约数与最小公倍数的方法示例

    java求最大公约数与最小公倍数的方法示例

    这篇文章主要介绍了java求最大公约数与最小公倍数的方法,涉及java数值运算的相关操作技巧,并附带分析了eclipse环境下设置运行输入参数的相关操作技巧,需要的朋友可以参考下
    2017-11-11
  • Java 数据结构之堆的概念与应用

    Java 数据结构之堆的概念与应用

    堆是一颗完全二叉树,在这棵树中,所有父节点都满足大于等于其子节点的堆叫大根堆,所有父节点都满足小于等于其子节点的堆叫小根堆,堆虽然是一颗树,但是通常存放在一个数组中,父节点和孩子节点的父子关系通过数组下标来确定
    2021-10-10
  • javaweb页面附件、图片下载及打开(实现方法)

    javaweb页面附件、图片下载及打开(实现方法)

    下面小编就为大家带来一篇javaweb页面附件、图片下载及打开(实现方法)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Open Feign之非SpringCloud方式使用示例

    Open Feign之非SpringCloud方式使用示例

    这篇文章主要为大家介绍了Open Feign之非SpringCloud方式使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • 详解IntelliJ IDEA 自定义方法注解模板

    详解IntelliJ IDEA 自定义方法注解模板

    本篇文章主要介绍了IntelliJ IDEA 自定义方法注解模板,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • idea插件无法下载4的种解决方式

    idea插件无法下载4的种解决方式

    这篇文章主要介绍了idea插件无法下载4的种解决方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • java通过jni调用opencv处理图像的方法

    java通过jni调用opencv处理图像的方法

    今天小编就为大家分享一篇java通过jni调用opencv处理图像的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-08-08
  • Spring @Bean 修饰方法时注入参数的操作方法

    Spring @Bean 修饰方法时注入参数的操作方法

    对于 Spring 而言,IOC 容器中的 Bean 对象的创建和使用是一大重点,Spring 也为我们提供了注解方式创建 bean 对象:使用 @Bean,这篇文章主要介绍了Spring @Bean 修饰方法时如何注入参数,需要的朋友可以参考下
    2023-10-10
  • JAVA十大排序算法之快速排序详解

    JAVA十大排序算法之快速排序详解

    这篇文章主要介绍了java中的快速排序,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08

最新评论