spring依赖注入详解(上)

news2024/12/23 13:48:09

一、Bean销毁的过程

如果bean销毁时会执行的场景

1、设置DestroyMethodName为(inferred)

// 先把DestroyMethodName设置为(inferred)
@Component
public class TestBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		beanDefinition.setDestroyMethodName("(inferred)");
	}
}

@Component
public class UserService {

    // spring优先会选择执行close(),close()和shutdown()写一个即可,spring会来调用
	public void close() {
		System.out.println(123);
	}

	public void shutdown() {
		System.out.println(321);
	}
}

        // 测试
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		applicationContext.close();

 2、实现DisposableBean接口

@Component
public class UserService implements DisposableBean {
	
	@Override
	public void destroy() throws Exception {
		System.out.println("123");
	}
}

// 测试
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		applicationContext.close();

3、实现AutoCloseable接口

@Component
public class UserService implements AutoCloseable {

	@Override
	public void close() throws Exception {
		System.out.println(123);
	}
}

// 测试
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		applicationContext.close();

二、依赖注入

 1、依赖注入方式

  1. 手动注入
  2. 自动注入
手动注入

在XML中定义Bean时,就是手动注入,因为是程序员手动给某个属性指定了值

<bean name="userService" class="com.spring.service.UserService">
 <property name="orderService" ref="orderService"/>
</bean>

上面这种底层是通过set方法进行注入。

<bean name="userService" class="com.spring.service.UserService">
 <constructor-arg index="0" ref="orderService"/>
</bean>

上面这种底层是通过构造方法进行注入。

所以手动注入的底层也就是分为两种:

  1. set方法注入
  2. 构造方法注入
自动注入

自动注入又分为两种:

  • XML的autowire自动注入

在XML中,我们可以在定义一个Bean时去指定这个Bean的自动注入模式:

  1. byType
  2. byName
  3. constructor
  4. default
  5. no

比如:

<bean id="userService" class="com.spring.service.UserService" autowire="byType"/>

这么写,表示Spring会自动的给userService中所有的属性自动赋值(不需要这个属性上有@Autowired注解,但需要这个属性有对应的set方法)。

在创建Bean的过程中,在填充属性时,Spring会去解析当前类,把当前类的所有方法都解析出来,Spring会去解析每个方法得到对应的PropertyDescriptor对象,PropertyDescriptor中有几个属性:

 

  1. name:这个name并不是方法的名字,而是拿方法名字进过处理后的名字
    1. 如果方法名字以“get”开头,比如“getXXX”,那么name=XXX
    2. 如果方法名字以“is”开头,比如“isXXX”,那么name=XXX
    3. 如果方法名字以“set”开头,比如“setXXX”,那么name=XXX
  2. readMethodRef:表示get方法的Method对象的引用
  3. readMethodName:表示get方法的名字
  4. writeMethodRef:表示set方法的Method对象的引用
  5. writeMethodName:表示set方法的名字
  6. propertyTypeRef:如果有get方法那么对应的就是返回值的类型,如果是set方法那么对应的就是set方法中唯一参数的类型

get方法的定义是: 方法参数个数为0个,并且 (方法名字以"get"开头 或者 方法名字以"is"开头并且方法的返回类型为boolean)

**set方法的定义是:**方法参数个数为1个,并且 (方法名字以"set"开头并且方法返回类型为void)

  • @Autowired注解的自动注入

上文说了@Autowired注解,是byType和byName的结合。

@Autowired注解可以写在:

  1. 属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
  2. 构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
  3. set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个

而这种底层到了:

  1. 属性注入
  2. set方法注入
  3. 构造方法注入

2、寻找注入点

在创建一个Bean的过程中,Spring会利用AutowiredAnnotationBeanPostProcessor的**postProcessMergedBeanDefinition()**找出注入点并缓存,找注入点的流程为:

  1. 遍历当前类的所有的属性字段Field
  2. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段是一个注入点
  3. 如果字段是static的,则不进行注入
  4. 获取@Autowired中的required属性的值
  5. 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到currElements集合中。
  6. 遍历当前类的所有方法Method
  7. 判断当前Method是否是桥接方法,如果是找到原方法
  8. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法是一个注入点
  9. 如果方法是static的,则不进行注入
  10. 获取@Autowired中的required属性的值
  11. 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到currElements集合中。
  12. 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。
  13. 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合对象,并缓存。

3、static的字段或方法为什么不支持

@Component
@Scope("prototype")
public class OrderService {

}

@Component
@Scope("prototype")
public class UserService  {

 @Autowired
 private static OrderService orderService;

 public void test() {
  System.out.println("test123");
 }

}

UserService userService1 = context.getBean("userService")
UserService userService2 = context.getBean("userService")

打印的都是一样

4、注入点进行注入

Spring在AutowiredAnnotationBeanPostProcessor的**postProcessProperties()**方法中,会遍历所找到的注入点依次进行注入。

字段注入
  1. 遍历所有的AutowiredFieldElement对象。
  2. 将对应的字段封装为DependencyDescriptor对象
  3. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。
  4. DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
  5. 利用反射将结果对象赋值给字段。

Set方法注入
  1. 遍历所有的AutowiredMethodElement对象
  2. 遍历将对应的方法的参数,将每个参数封装成MethodParameter对象
  3. MethodParameter对象封装为DependencyDescriptor对象
  4. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。
  5. DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
  6. 利用反射将找到的所有结果对象传给当前方法,并执行。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hive(一)

一、DDL 1、数据库操作 1&#xff09;、创建数据库 语法&#xff1a; CREATE DATABASE [IF NOT EXISTS] database_name [COMMENT database_comment] [LOCATION hdfs_path] [WITH DBPROPERTIES (property_nameproperty_value, ...)]; 案例&#xff1a; &#xff08;1&…

vue element-ui 菜单管理使用图标选择器组件

目录 &#x1f31f;前言&#x1f31f;安装&#x1f31f;main.js配置&#x1f31f;页面使用&#x1f31f;效果展示 &#x1f31f;前言 哈喽小伙伴们&#xff0c;本文为大家介绍一下 VueElementUI 中图标选择器组件的使用方法&#xff1b;一起来看下吧。 &#x1f31f;安装 np…

RN 尝鲜之旅

React Native 一直没使用过&#xff0c;闲来无事&#xff0c;还是尝鲜了一下下。 目前还没有出新手村&#xff0c;所以写的东西不一定具有任何参考价值&#xff0c;见谅。 关于 RN 的一些说明 RN 与 R RN 与 R 的区别&#xff1a;来自掘金的一篇文章 RN 与 R 不一样&#xf…

报道 | 9月国际运筹优化会议汇总

封面图来源&#xff1a; https://www.pexels.com/zh-cn/photo/1181406/ 九月召开会议汇总&#xff1a; The 96th meeting of the EURO Working Group on Multiple Criteria Decision Aiding (EWG-MCDA) Location: Paris, France Important dates: Conference: September 202…

嵌入式系统常用的开发板

今天&#xff0c;了解一下常用的开发板&#xff0c;像stm32是最近了解的&#xff0c;esp8266系列是之前大三下上物联网导论课程时候接触的&#xff0c;一些树莓派&#xff0c;Arduino听说过&#xff0c;但了解不多。

MySQL索引常见术语(索引下推、索引覆盖、最左匹配等)

一:背景 我们在面试中都知道,对于MySQL索引是必问的。大家也应该都知道MySQL的数据结构,什么是索引。其中在面试中,面试官也经常问,你做过哪些优化?本文主要是介绍MySQL索引的一些常见术语,比如索引下推、索引覆盖、最左匹配等,这些其实也是MySQL优化的一部分,能够熟练…

谷歌浏览器推出全新功能:可自动检测恶意软件!

近日&#xff0c;谷歌正在测试 Chrome 浏览器的一项新功能。该功能可在已安装的扩展程序从 Chrome 网上商城删除时向用户发出恶意软件提示警告。 在Chrome 应用商店里一直有人源源不断的发布浏览器扩展程序&#xff0c;有很多都会通过弹出式广告和重定向广告进行推广。 这些扩…

社交工程和钓鱼攻击防范: 分析针对人类心理和社交工程的攻击技术,并介绍预防这些攻击的方法

第一章&#xff1a;引言 随着科技的不断进步&#xff0c;网络安全问题愈发凸显。在这个数字化时代&#xff0c;社交工程和钓鱼攻击成为黑客们获取敏感信息的常用手段。这些攻击不是基于技术漏洞&#xff0c;而是利用人类心理弱点来进行。本文将深入探讨社交工程和钓鱼攻击的原…

一个改进型的差分运放分析

在使用单个集成运放构成的加减运算电路时&#xff0c;存在两个缺点&#xff1a;一是电阻的选取和调整不方便&#xff0c;而是对于每个信号源的输入电阻均较小&#xff08;即相对于信号源内阻&#xff0c;电路的输入阻抗较小&#xff09;。 因此可以采用下图的两级电路实现差分比…

Obsidian 入门使用手册

文章目录 一、Obsidian 入门1.1 什么是 Obsidian1.2 安装 Obsidian 二、Obsidian 配置2.1 创建第一个笔记2.2 设置界面语言使用中文2.3 主题 三、小结 一、Obsidian 入门 1.1 什么是 Obsidian Obsidian 是一款基于 Markdown 语法编辑的笔记软件。与传统的 Markdown 软件不同的…

图神经网络与分子表征:1. 分子图和图神经网络基础

CSDN的朋友们大家好&#xff0c;好久没写系列文章了。 近期读了很多图神经网络&#xff08;GNN&#xff09;和分子表征&#xff08;molecular representation&#xff09;的论文&#xff0c;正好最近不是很忙&#xff0c;所以我决定把自己的学习过程记录下来&#xff0c;与大家…

Python 在logging.config.dictConfig()日志配置方式下,使用自定义的Handler处理程序

文章目录 一、基于 RotatingFileHandler 的自定义处理程序二、基于 TimedRotatingFileHandler 的自定义处理程序 Python logging模块的基本使用、进阶使用详解 Python logging.handlers模块&#xff0c;RotatingFileHandler、TimedRotatingFileHandler 处理器各参数详细介绍 …

pandas连接查询

df1数据如下 df2数据如下 连接查询代码 -1 import pandas as pddf1 pd.DataFrame({id:[1001,1002,1003,1004],name:[Hu,Dotu,Evp,Swe]}) df2 pd.DataFrame({id:[1001,1001,1003,1004, 1003],course:[c1,c2,c3,c2,c1],score:[100, 98, 64, 84, 69]})result pd.merge(df1, df…

【C++初阶】vector容器

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

0007Java程序设计-jsp问卷调查系统设计与实现

摘 要 随着社会不断进步与发展&#xff0c;生活节奏不断加快&#xff0c;信息已经成为我们生活中不可缺少的一部分&#xff0c;很多企业需要掌握大量的信息来了解特定用户的需求&#xff0c;传统的做法是组织大量的人力物力对用户散发调查表&#xff0c;然后对收集的信息进行统…

python 基础篇 day 1 初识变量和数据类型

文章目录 变量变量作用——用于存储和表示数据。变量命名规则命名法大驼峰小驼峰下划体n j i a x 通常作为临时变量使用 建议 变量种类全局变量&#xff08;Global Variables&#xff09;局部变量&#xff08;Local Variables&#xff09;静态变量&#xff08;Static Variables…

linux常用基础命令与文件结构汇总

1 学习目标 说出Linux下的目录结构和常见目录的作用熟练使用Linux下的相对路径和绝对路径熟练使用Linux下常用文件和目录操作相关的命令熟练使用修改用户权限、用户和用户组相关的命令熟练使用文件的查找和检索相关的命令熟练掌握Ubuntu下的软件安装和卸载熟练使用压缩工具完成…

七夕节日表白:七大网页风格与其适用人群

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

YOLOv5源码中的参数超详细解析(5)— 验证部分val(test).py

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。YOLOv5项目代码中&#xff0c;val.py 是一个代表验证&#xff08;validation&#xff09;的 Python 脚本文件名。通常在机器学习或深度学习的任务中&#xff0c;我们会将数据集分为训练集和验证集&#xff0c;使用训练集来…

请说人话!如何理解基本分页存储管理

一、默认设定 &#xff08;一&#xff09;按字节编制一个房间可以装8只猪猪 现在的计算机一般都是按字节编址的。这个不理解的话&#xff0c;可以看我的文章为什么20位地址总线决定寻址空间是1MB“http://t.csdn.cn/Eo2nE” &#xff08;二&#xff09;内存采用非连续分配方…