@Autowired和@Resource注解之间的关系区别,Bean的作用域和生命周期,Spring的执行流程

目录

一. @Autowired 和 @Resource 注解

二. Bean的作用域 

1. singleton(单例模式)

2. prototype(原型模式)(多例模式)

3. 请求作用域:request

4. 会话作用域:session

三. Spring 的执行流程

四. Bean 的生命周期 

 1. 实例化

 2. 设置属性 

3. Bean 初始化  

   3.1 执行各种各种 Aware 通知; 

   3.2 执行初始化前置方法;

   3.3 执行初始化方法;

   3.4 执行初始化后置方法; 

4. 使用 Bean 对象

5. 销毁 Bean 对象 

6. 代码演示 


一. @Autowired 和 @Resource 注解

在前面的文章中,我们介绍了通过 @Autowired 注解的方式来获取到Spring容器中的Bean对象,实际上,还有另一个注解:@Resource,它的功能也是差不多的,也可以从 Spring容器中获取到Bean对象,但也是存在一定的差别的。 

  1. @Resource 来自于 jdk,而 @Autowired 来自于 Spring;
  2. 使⽤时设置的参数不同:相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如
    name 设置,根据名称获取 Bean;
  3. @Autowired 可⽤于 Setter 注⼊、构造函数注⼊和属性注⼊,⽽ @Resource 只能⽤于 Setter 注⼊和属性注⼊,不能⽤于构造函数注⼊;
  4. @Autowired在获取Bean对象的时候,先根据类型查找,之后再根据名称查找;而@Resource先根据名称查找,之后再根据类型查找;

问题分析:当在 Spring 中存放多个同一类型 Bean 对象的时候,使用 @Autowired 去获取 Bean对象会出错。

@Component
public class UserBeans {
    @Bean
    public User user1(){
        User user = new User();
        user.setAge(20);
        user.setId(1);
        user.setName("张三");
        return user;
    }

    @Bean
    public User user2(){
        User user = new User();
        user.setAge(22);
        user.setId(11);
        user.setName("李四");
        return user;
    }
}
@Controller
public class UserController2 {
    @Autowired
    private User user;

    public void sayHi(){
        System.out.println("do UserController2");
        System.out.println(user.getName());
    }
}

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

此时执行是会报错的,因为 @Autowired 注解先通过类型去查找,得到了 user1 和 user2 两个 Bean对象,但是根据 user 名称来去查找的话,是没有找到对应的 Bean 对象的,因此会报错。(查找 Bean 对象的默认名称为 添加 @Autowired 注解的对应属性名称,也就是上述第二段代码的private User user

 解决办法1:修改 @Autowired 注解的对应属性名称

@Controller
public class UserController2 {
    @Autowired
    private User user1;

    public void sayHi(){
        System.out.println("do UserController2");
        System.out.println(user1.getName());
    }
}

此时运行代码就会获取到对应的 Bean对象,也就是存储的 user1 对象。

 

解决办法2:配合使⽤ @Qualifier 注解定义名称

@Qualifier(value = "Bean对象的名称") 

@Controller
public class UserController2 {
    @Autowired
    @Qualifier(value="user1")
    private User user;

    public void sayHi(){
        System.out.println("do UserController2");
        System.out.println(user.getName());
    }
}

也可以得到预期的结果。 

 

解决办法3:使⽤ @Resource(name="Bean对象名称") 定义

@Controller
public class UserController2 {
    
    @Resource(name="user1")
    private User user;

    public void sayHi(){
        System.out.println("do UserController2");
        System.out.println(user.getName());
    }
}

 同样是可以得到预期结果的。

 

二. Bean的作用域 

限定程序中变量的可⽤范围叫做作用域,或者说在源代码中定义变量的某个区域就叫做作用域。而 Bean 的作⽤域是指 Bean 在 Spring 整个框架中的某种行为模式。

1. singleton(单例模式)

singleton 表示的是单例作用域,类似于之前讲过的单例模式。这也是默认情况下的行为模式。在该作用域下的 Bean 在 IoC容器中只存在一个实例,获取到的 Bean 以及对 Bean 进行修改,都是针对同一个 Bean 对象。

代码演示: 

1. 往 Spring 容器中注入一个 User 对象 

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

2.  通过@Autowired获取到Bean对象,并对其进行修改

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

    public void printUser(){
        System.out.println(user);
        // 修改 User
        User myUser = user;     // 给引用对象赋值,其实就是共享对象!!!这两个变量指向了同一个地址
        myUser.setName("李四");
        System.out.println("myUser -> " + myUser);
        System.out.println("User -> " + user);  
    }
}

3. 再新建一个类,通过 @Autowired 获取到Bean对象 


@Controller
public class UserController2 {

    @Resource
    private User user;

    public void printUser2(){
        System.out.println("user -> " + user);  
        // Bean 作用域 -> 默认是单例模式 = 此 Bean 在整个框架(Spring 容器)中只有一份
    }
}

 4. 最后输出观察结果


public class App {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        UserController userController = context.getBean("userController",UserController.class);
        userController.printUser();

        UserController2 userController2 = context.getBean("userController2",UserController2.class);
        userController2.printUser2();

    }
}

因此也可以得出结论:singleton 单例作用域,他们使用的 Bean 都是 Spring 容器中的同一个对象。这个 Bean 在整个 Spring 中只有一份,是全局共享的,当其他人修改了这个值之后,那么另一个人读到的就是被修改后的值了。

2. prototype(原型模式)(多例模式)

 在原型模式下,每次对该作用域下的 Bean 的请求都会创建新的实例,也就是说每次获取 Bean 对象和修改 Bean 对象都是针对新的 Bean 对象实例而言的。

需要添加注解 @Scope("prototype") 或者@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

代码演示: 

@Component
public class UserBeans {
    @Bean
    @Scope("prototype")
    //@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public User user(){
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}

 再次运行得到结果:

可以看出,在第二次通过 @Autowired 获取到 Bean 对象的时候,得到的是一个新的实例对象了。

3. 请求作用域:request

 每次 http 请求会创建新的 Bean 实例。适用于⼀次 http 的请求和响应的共享 Bean 的情况。

 限定SpringMVC中使⽤。

4. 会话作用域:session

在⼀个http session中,定义⼀个 Bean 实例。每次 Session 会话共享一个 Bean 对象。限定SpringMVC中使⽤。

 

三. Spring 的执行流程

 

 

四. Bean 的生命周期 

 1. 实例化

给 Bean 对象分配内存空间。 

此处要注意:初始化不等于实例化!!!

类的初始化是完成程序前的准备工作,在这个阶段,静态的会被执行,同时会开辟一块存储空间用来存放静态的数据,初始化只在类加载的时候执行一次,也可以理解为给对象赋值的过程。

类的实例化,是指创建一个对象的过程,这个过程会在堆中开辟内存,将一些非静态的方法,变量存放在里面,在程序执行的过程中,可以创建多个对象,即多次实例化,每次实例化都会开辟一块新的内存。 

 2. 设置属性 

看需求,有的 Bean 对象需要被注入属性,这个属性也会是已经在 Spring 容器中的 Bean,如果该属性还不存在于 Spring 中,那么会先去将该属性 Bean 存储到 Spring 中。 

3. Bean 初始化  

   3.1 执行各种各种 Aware 通知; 

实现了各种 Aware 通知的⽅法,如 BeanNameAware、BeanFactoryAware、
ApplicationContextAware 的接⼝⽅法;

   3.2 执行初始化前置方法;

   3.3 执行初始化方法;

有两种方式,第一种是通过注解 @PostConstruct ,依赖注⼊操作之后执行注解修饰的方法;第二种是通过 xml 的方式,执行自己指定的 init-method ⽅法。如果两者都存在,那么先执行注解的初始化方法。

 

   3.4 执行初始化后置方法; 

 

4. 使用 Bean 对象

通过 getBean() 方法来获取容器中的 Bean 对象并使用。 

5. 销毁 Bean 对象 

销毁容器的各种⽅法,如 @PreDestroy、DisposableBean 接⼝⽅法、destroy-method(XML的方式)。  

6. 代码演示 

public class App {
    public static void main(String[] args) {
// 此时要使用 ApplicationContext 的子类,因为它本身是没有销毁方法的
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        BeanComponent beanComponent = context.getBean("beanComponent",BeanComponent.class);
        beanComponent.sayHi();
        context.close();
    }
}

public class BeanComponent implements BeanNameAware {
    @Override
    public void setBeanName(String s) {
        System.out.println("执行了通知 BeanName -> " + s);
    }

    /**
     * xml 方式的初始化方法
     */
    public void myInit(){
        System.out.println("XML 方式初始化");
    }


    @PostConstruct
    public void doPostConstruct(){
        System.out.println("注解的初始化方法");
    }

    public void sayHi(){
        System.out.println("执行 sayHi()");
    }

    // 销毁的方法,销毁的时候执行的一个方法
    @PreDestroy
    public void doPreDestroy(){
        System.out.println("do PreDestroy");
    }
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/16471.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

函数的栈帧与销毁(栈帧可不是战争哦)

🤩本文作者:大家好,我是paperjie,感谢你阅读本文,欢迎一建三连哦。 🥰内容专栏:这里是《C语言》专栏,笔者用重金(时间和精力)打造,将C语言知识一网打尽,希望可…

【算法】最容易懂得的红黑树

红黑树是一个平衡的二叉树,但不是一个完美的平衡二叉树。虽然我们希望一个所有查找都能在~lgN次比较内结束,但是这样在动态插入中保持树的完美平衡代价太高,所以,我们稍微放松逛一下限制,希望找到一个能在对数时间内完…

PS学习笔记(零基础PS学习教程)

很多新手学习PS不知从何下手,做设计的第一阶段肯定是打牢基础,把工具用熟练;本期特别为大家整理了PS入门的学习笔记,把每个工具的用法整理了下来,在使用过程中有哪里不清楚的可以翻看来看看~ 一、ps的工作界面的介绍 …

Python程序员想要转行,可以从这几个方面着手

最近有很多朋友问我一个问题,不论是我们做程序员还是做产品经理或者其他行业,到了30岁或35岁之后,都会面临各种各样的问题,比如达到职业天花板。有没有一种方法能够解决这种问题呢?我想分享一下我的观点和身边的案例。…

网络攻击与防御

1.什么是数据认证,有什么作用,有哪些实现的技术手段? 数字认证证书它是以数字证书为核心的加密技术可以对网络上传输的信息进行加密和解密、数字签名和签名验证,确保网上传递信息的安全性、完整性。 使用了数字证书,即使您发送的…

ChatGPT是什么?ChatGPT里的G、P、T分别指什么

文章目录 ChatGPT是什么GTP中的 生成式 是什么意思GTP中的 预训练 是什么意思GTP中的 变换模型 是什么意思 什么是Transformer什么是注意力机制 监督学Xi、无监督学Xi、强化学Xi ChatGPT是什么 GPT: Generative Pre-trained Transformer 生成式预训练变换模型 ChatGPT是由Ope…

用ChatGPT问DotNet的相关问题,发现DotNet工程师的前景还不错

本人最近费了九牛二虎之力注册了一个ChatGPT账号,现在就给大家分享一下,问一下关于.NET的问题,看看ChatGPT的AI功能具体如何? 一、C#跟其它语言比较的优势 回答: C#是一门编程语言,它是为 Microsoft 的 …

第十三章 移动和旋转(上)

移动和旋转是游戏对象最频繁地操作。我们上个章节简单介绍了Cube的移动和旋转。移动是修改transform的position属性,旋转是修改transform的eulerAngles(欧拉角)属性,两者属性值均可以使用Vector3向量来实现。需要大家注意的是&…

B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能

B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能 文章目录 B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能每博一文案1. Cookie 的概述2. session 与 Cookie 之间的联系:3. Cookie 的作用&#xff…

盈泰德带你了解产品表面缺陷检测系统

与前几年相比,机器视觉行业在表面检测方面有了很大的突破。检测产品表面的划痕、污渍不再困难,广泛应用于金属、玻璃、手机屏幕、液晶面板等行业的表面检测。 机器视觉检测有以下四种常用的检查和照明方法: 同轴照明、低角度照明、背光照明…

Python一行命令搭建HTTP服务器并外网访问 - 内网穿透

文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 转载自远程内网穿透的文章:【Python】快速简单搭建HTTP服务器并公网访问「cpolar内网穿透…

Java 基础进阶篇(五)—— 抽象类与模板方法设计模式

文章目录 一、抽象类、抽象方法概述二、抽象类的特征三、模板方法设计模式3.1使用场景3.2 实现步骤3.3 写作文案例 补充:final 和 abstract 是什么关系? 一、抽象类、抽象方法概述 在 Java 中 abstract 是抽象的意思,可以修饰类、成员方法。 abstract …

win10远程桌面控制Ubuntu服务器 - 内网穿透实现公网远程

文章目录 前言视频教程1. ubuntu安装XRDP2.局域网测试连接3. Ubuntu安装cpolar内网穿透4.cpolar公网地址测试访问5.固定域名公网地址 转载自远程穿透文章:Windows通过RDP异地远程桌面Ubuntu【内网穿透】 前言 XRDP是一种开源工具,它允许用户通过Windows…

机械硬盘(HDD)与固态硬盘(SSD)

目录 机械硬盘(HDD) 最小组成单元是扇区 硬盘结构 硬盘工作原理 硬盘上的数据组织 硬盘指标 影响性能的因素 固态硬盘(SSD) 最小存储单元是Cell SSD的特点 SSD架构 NAND Flash 闪存介质 地址映射管理 FTL闪存转换层 机械硬盘&…

JAVA IO 模型详解

什么是IO I/O(Input/Outpu) 即输入/输出 。 从计算机结构的视角来看的话, I/O 描述了计算机系统与外部设备之间通信的过程。 从应用程序的视角来看的话,我们的应用程序对操作系统的内核发起 IO 调用(系统调…

微信小程序定义模板

微信小程序提供模板(template)功能,把一些可以共用的,复用的代码在模板中定义为代码片段,然后在不同的地方调用,可以实现一次编写,多次引用的效果。 首先我们看一下官网是如何操作的 一般的情…

JavaWeb学习--RequestResponse

目录 JavaWeb学习--Request&Response 1,Request和Response的概述 request:获取请求数据 response:设置响应数据 **小结** 2,Request对象 **小结** 2.2 Request获取请求数据 **小结** 2.4 请求参数中文乱码问题 URL编码 2.5 Request请求转…

【前端技术】Vue3 01:初识 Vue.js

Vue 可以说是非常流行了,至少在国内是这样,他是个轻量级的 JavaScript 框架,非常适合构建大型和中小型的 Web 应用程序,如果想和前端打交道,应该绕不过这个框架吧。 目录 1 Vue.js 介绍 2 IDE 选择 2.1 vscode 2.…

Eplan 部件库导入部件的方法

1. 部件宏文件如何下载 1.1 西门子部件宏文件下载 EPLAN 的部件库是可以更新的,一般元器件厂商会提供其部件文件,以 SIEMENS 为例 进入网站,点击EPLAN 的图标 https://www.automation.siemens.com/bilddb/index.aspx?lang=en 在订货号中输入所需部件订货号,点击搜索。点…

【Java笔试强训 27】

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥 不用加…