【Java基础】day13

2023-11-20

day13

一、Spring Bean 生命周期是怎样的?

详细过程分为以下几个步骤:

① 初始化 Bean

容器通过获取 BeanDefinition 中的信息进行实例化,这一步仅仅是简单的实例化,并没有进行依赖注入。

实例化的对象被包装在 BeanWrapper 对象中,BeanWrapper 提供了设置对象属性的接口,从而避免了使用反射机制来注入属性。

② 设置对象属性(依赖注入)

实例化后的 Bean 仍是一个原生的状态,然后 Spring 根据 BeanDefinition 中的信息进行依赖注入,并且通过 BeanWrapper 提供的设置属性的接口完成依赖注入。

③ 注入 Aware 接口

Spring 会检测该对象是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给 bean。

  • BeanNameAware:通过 Bean 的引用来获取 Bean 的 ID,一般业务中很少使用;
  • BeanFactoryAware:获取 Spring BeanFactory 容器,如发布事件等;
  • ApplicationContextAwaer:获取 Spring ApplicationContext 容器;

④ BeanPostProcessor 前置处理

如果 Spring 实现了 BeanPostProcessor 接口,pring 将调用它们的 postProcessBeforeInitialization(Object bean, String beanName)(预初始化)方法,作用是在 Bean 实例创建成功后对进行增强处理,如对 Bean 进行修改,增加某个功能。

⑤ InitializingBean 接口

InitializingBean 接口只有一个函数:afterPropertiesSet(),作用是在 bean 正式构造完成前增加我们自己自定义的逻辑,与前置处理不同,该函数的入参没有 bean 对象, 因为无法处理 bean 对象本身,只能增加一些额外的逻辑。

⑥ init-method 声明

作用同 InitializingBean 接口。

⑦ BeanPostProcessor 后置处理

如果 Spring 实现了 BeanPostProcessor 接口,Spring 将调用它们的 postProcessAfterInitialization(Object bean, String beanName)(预初始化)方法,作用与 4 的一样,只不过初始化方法声明是在 Bean 初始化前执行的,而这个是在 Bean 初始化后执行的,时机不同。

⑧ Bean 初始化完成

经过以上的工作后,Bean 将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁。

⑨ DispostbleBean 接口

DispostbleBean 接口只有一个函数:destroy() 在 bean 被销毁前执行此函数里的逻辑。

⑩ destroy-method 声明

作用同 DispostbleBean 接口。

简单描述分为以下几个步骤:

  • 实例化:通过反射去推断构造函数进行实例化,主要使用的是 doCreateBean() 方法

    • 一般有静态工厂、实例工厂的方式进行实例化
  • 属性赋值:解析自动装配(byName、byType、Constructor、@Autowired)

    • 是 DI 的体现,将依赖的对象/属性值注入到需要创建的对象中
  • 初始化:

    • 调用 xxxAware 回调方法,这个过程是一个渐进过程,只有实现了 Aware 接口才会去调用,依此如下

      • 调用 BeanNameAware 的 setBeanName() 方法
      • 调用 BeanFactoryAware 的 setBeanFactory() 方法
      • 调用 ApplicationContextAware 的 setApplicationContext() 方法
    • Aware 接口实现之后,调用 BeanPostProcessor 的预初始化方法。调用 InitializingBean 的 afterPropertiesSet() 方法,调用定制的初始化方法,调用 BeanPostProcessor 的后初始化方法。(调用初始化生命周期回调,有三种方式,此处是其一)初始化生命周期回调另外两种方式:① XML 文件中指定 <init-method>;② 用注解 @PostConstructor 实现初始化生命周期回调

    • 如果 Bean 实现了 AOP,会在这一步创建动态代理

  • 销毁

    • Spring 容器关闭的时候进行调用

    • 调用销毁生命周期回调(三种方式)

      • 实现 Disposable 接口的 destroy() 方法
      • XML 配置文件中配置 <destroy-method>
      • 使用注解 @PreDestory 创造销毁前置方法

二、Spring Boot 的自动装配原理是什么?

启动类上标注的 @SpringBootApplication 注解,实际上内部会有一个 @EnableAutoConfiguation 注解。

Spring Boot 通过 @EnableAutoConfiguration 开启自动装配,通过 SpringFactoriesLoader 最终加载 META-INF/spring.factories 中的自动配置类实现自动装配,自动配置类其实就是通过 @Conditional 按需加载的配置类,想要其生效必须引入 spring-boot-starter-xxx 包实现起步依赖。

三、BeanDefinition 中保存的是什么?

BeanDefinition 包含了对 Bean 的所有描述信息,是 Spring IoC 容器保存 Bean 的基本数据结构。同时对外提供了获取/修改 Bean 描述的各种方法。BeanDefinition 包装了需要让 IoC 容器管理的 Bean 对象的数据信息:依赖关系,创建方式,加载方式等。

通常项目启动时,IoC 容器启动扫描路径,根据配置将需要容器管理的 Bean 信息装配成 BeanDefinition 对象。在 getBean 时通过反射将 BeanDefinition 中的 beanClass 创建、初始化赋值、依赖注入等操作,通过这种方式让 IoC 容器控制 Bean 的创建、初始化、销毁。
用来存储 Bean 的定义信息,用来决定 Bean 的生产方式。

定义信息包括:Bean 的类别、父类名称、BeanClass 名称、Scope 、是否为懒加载、依赖对象、初始化/销毁方法名称;是否为单例、多例、抽象等。通常定义的 Bean 中,只有 singleton、非 abstract、非 lazy 的 Bean 才会在 IoC 容器被创建的时候加载。

BeanDefinition 的部分源代码如下:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    // 单例、原型标识符
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;        
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    
    // 标识 Bean 的类别,分别对应 1.用户定义的 Bean 2.来源于配置文件的 Bean 3.Spring 内部的 Bean
    int ROLE_APPLICATION = 0;
    int ROLE_SUPPORT = 1;
    int ROLE_INFRASTRUCTURE = 2;
    
    void setParentName(@Nullable String parentName);
    void setBeanClassName(@Nullable String beanClassName);
    void setScope(@Nullable String scope);
    void setLazyInit(boolean lazyInit);
    boolean isLazyInit();
    void setDependsOn(@Nullable String... dependsOn);
    void setAutowireCandidate(boolean autowireCandidate);
    boolean isAutowireCandidate();
    void setPrimary(boolean primary);
    boolean isPrimary();
    void setFactoryBeanName(@Nullable String factoryBeanName);
    void setFactoryMethodName(@Nullable String factoryMethodName);

    ConstructorArgumentValues getConstructorArgumentValues();
    default boolean hasConstructorArgumentValues() {
            return !getConstructorArgumentValues().isEmpty();
    }
    MutablePropertyValues getPropertyValues();
    default boolean hasPropertyValues() {
            return !getPropertyValues().isEmpty();
    }

    void setInitMethodName(@Nullable String initMethodName);
    void setDestroyMethodName(@Nullable String destroyMethodName);
    void setRole(int role);
    void setDescription(@Nullable String description);
    ResolvableType getResolvableType();

    boolean isSingleton();
    boolean isPrototype();
    boolean isAbstract();
    // 其他的一些方法和属性...
}

四、BeanName 的生成规则?

Bean 的名称一般是通过使用 BeanNameGenerator 接口来实现,其下面存在两个实现类,包括 AnnotationBeanNameGeneratorDefaultBeanNameGenerator

Bean 将自己的全路径类名作为自己的 Bean 名字。如果没有类名,那就看是否有父 Bean;如果有,假设父 Bean 名字为 hehe,那么就用 hehe$child 作为此子 Bean 的名字;如果没有父 Bean,那就看 Bean 的工厂 Bean 的名字。如果有,假设工厂 Bean 名字为 haha,那么 Bean 的名字就是 haha$created;如果没有工厂,那就报错:既没有自己的类名、也没有父 Bean 类名、也没有工厂 Bean 类名。

Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unnamed bean definition specifies neither ‘class’ nor ‘parent’ nor ‘factory-bean’ - can’t generate beanName.

这种情况,通常是存在没有定义的 Bean,多见于配置文件的 Bean 中。

不管最终用的是哪一个的名字,需要对这个名字进行唯一性检查。如果已经有这个名字存在了,那就在名字后面加上 #1#num)格式的字符,这样每个 Bean 的名字就是唯一的了。# 后面的数字,使用一个 counter 来维护,保持数字在相同的前缀名称下不会发生重复。

Reference

https://blog.csdn.net/dgh112233/article/details/102919658

五、JDK 动态代理和 CGLib 动态代理的实现?

JDK 动态代理使用 Java 反射包中的类和接口实现动态代理的功能,主要涉及三个类:InvocationHandlerMethodproxy

  • JDK 动态代理使用 Java 反射技术进行操作,在生成类上更高效。
  • JDK 动态代理只能对接口进行代理,这是因为 JDK 动态代理生成的代理类,其父类是 Proxy,且 Java 不支持类的多继承。

CGLIB Code Generation Library 通过动态生成一个需要被代理类的子类,即被代理类作为父类。该子类重写被代理类的所有不是 final 修饰的方法,并在子类中采用方法拦截的技术拦截父类所有的方法调用,进而织入横切逻辑。在底层实现上,CGLIB 使用字节码处理框架 ASM,该框架用于转换字节码并生成新的类。之后将新的类字节码文件通过类加载器加载到内存中,通过调用目标类实现动态代理。

  • CGLIB 能够代理接口和普通的类,但是被代理的类不能被 final 修饰,且接口中的方法不能使用 final 修饰。
  • CGLIB 使用 ASM 框架直接对字节码进行修改,使用了 FastClass 的特性。在某些情况下,类的方法执行会比较高效。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Java基础】day13 的相关文章

  • 如何在一行中将字符串数组转换为双精度数组

    我有一个字符串数组 String guaranteedOutput Arrays copyOf values values length String class 所有字符串值都是数字 数据应转换为Double QuestionJava 中
  • 如何测试 JUnit 测试的 Comparator?

    我需要测试 Compare 方法 但我对如何测试感到困惑 我可以看看该怎么做吗 public class MemberComparator implements Comparator
  • 线程自动利用多个CPU核心?

    假设我的应用程序运行 2 个线程 例如渲染线程和游戏更新线程 如果它在具有多核 CPU 当今典型 的移动设备上运行 我是否可以期望线程在可能的情况下自动分配给不同的核心 我知道底层操作系统内核 Android linux内核 决定调度 我的
  • ExceptionConverter:java.io.IOException:文档没有页面。我正在使用 iText

    当我执行下面的代码时 File f new File c sample pdf PdfWriter getInstance document new FileOutputStream f document open System out p
  • IntelliJ IDEA 创建的 JAR 文件无法运行

    我在 IntelliJ 中编写了一个跨越几个类的程序 当我在 IDE 中测试它时它运行良好 但是 每当我按照教程将项目制作成 jar 可执行文件时 它就不会运行 双击 out 文件夹中的文件时 该文件不会运行 并显示 无法启动 Java J
  • java.io.IOException: %1 不是有效的 Win32 应用程序

    我正在尝试对 XML 文档进行数字签名 为此我有两个选择 有一个由爱沙尼亚认证中心为程序员创建的库 还有一个由银行制作的运行 Java 代码的脚本 如果使用官方 认证中心 库 那么一切都会像魅力一样进行一些调整 但是当涉及到银行脚本时 它会
  • 在数据流模板中调用 waitUntilFinish() 后可以运行代码吗?

    我有一个批处理 Apache Beam 作业 它从 GCS 获取文件作为输入 我的目标是根据执行后管道的状态将文件移动到两个 GCS 存储桶之一 如果管道执行成功 则将文件移动到存储桶 A 否则 如果管道在执行过程中出现任何未处理的异常 则
  • 使用 ANTLR 为 java 源代码生成抽象语法树

    如何使用 ANTLR 从 java src 代码生成 AST 有什么帮助吗 好的 步骤如下 前往ANTLR站点 http www antlr org 并下载最新版本 下载Java g和JavaTreeParser g文件来自here htt
  • java中删除字符串中的特殊字符?

    如何删除字符串中除 之外的特殊字符 现在我用 replaceAll w s 它删除了所有特殊字符 但我想保留 谁能告诉我我该怎么办 Use replaceAll w s 我所做的是将下划线和连字符添加到正则表达式中 我添加了一个 连字符之前
  • 如何在 Java 中禁用 System.out 以提高速度

    我正在用 Java 编写一个模拟重力的程序 其中有一堆日志语句 到 System out 我的程序运行速度非常慢 我认为日志记录可能是部分原因 有什么方法可以禁用 System out 以便我的程序在打印时不会变慢 或者我是否必须手动检查并
  • OnClick 事件中的 finish() 如何工作?

    我有一个Activity一键退出Activity 通过layout xml我必须设置OnClick事件至cmd exit调用 this finish 效果很好 public void cmd exit View editLayout thi
  • Microsoft Graph 身份验证 - 委派权限

    我可以使用 Microsoft Graph 访问资源无需用户即可访问 https developer microsoft com en us graph docs concepts auth v2 service 但是 此方法不允许我访问需
  • 序列化对象以进行单元测试

    假设在单元测试中我需要一个对象 其中所有 50 个字段都设置了一些值 我不想手动设置所有这些字段 因为这需要时间而且很烦人 不知何故 我需要获得一个实例 其中所有字段都由一些非空值初始化 我有一个想法 如果我要调试一些代码 在某个时候我会得
  • Spring Data 与 Spring Data JPA 与 JdbcTemplate

    我有信心Spring Data and Spring Data JPA指的是相同的 但后来我在 youtube 上观看了一个关于他正在使用JdbcTemplate在那篇教程中 所以我在那里感到困惑 我想澄清一下两者之间有什么区别Spring
  • 归并排序中的递归:两次递归调用

    private void mergesort int low int high line 1 if low lt high line 2 int middle low high 2 line 3 mergesort low middle l
  • 如何在 JFreeChart TimeSeries 图表上显示降雨指数和温度?

    目前 我的 TimeSeries 图表每 2 秒显示一个位置的温度 现在 如果我想每2秒显示一次降雨指数和温度 我该如何实现呢 这是我的代码 import testWeatherService TestWeatherTimeLapseSer
  • 使用 AWS Java SDK 为现有 S3 对象设置 Expires 标头

    我正在更新 Amazon S3 存储桶中的现有对象以设置一些元数据 我想设置 HTTPExpires每个对象的标头以更好地处理 HTTP 1 0 客户端 我们正在使用AWS Java SDK http aws amazon com sdkf
  • 使用 SAX 进行 XML 解析 |如何处理特殊字符?

    我们有一个 JAVA 应用程序 可以从 SAP 系统中提取数据 解析数据并呈现给用户 使用 SAP JCo 连接器提取数据 最近我们抛出了一个异常 org xml sax SAXParseException 字符引用 是无效的 XML 字符
  • 如何在 Maven 中显示消息

    如何在 Maven 中显示消息 在ant中 我们确实有 echo 来显示消息 但是在maven中 我该怎么做呢 您可以使用 antrun 插件
  • Netbeans 8 不会重新加载静态 Thymeleaf 文件

    我通过 Maven 使用 Spring Boot 和 Thymeleaf 当我进行更改时 我似乎无法让 Netbeans 自动重新部署我的任何 Thymeleaf 模板文件 为了看到更改 我需要进行完整的清理 构建 运行 这需要太长的时间

随机推荐

  • 14-4_Qt 5.9 C++开发指南_QUdpSocket实现 UDP 通信_UDP组播

    文章目录 1 UDP组播的特性 2 UDP 组播实例程序的功能 3 组播功能的程序实现 4 源码 4 1 可视化UI设计 4 2 mainwindow h 4 3 mainwindow cpp 1 UDP组播的特性 下图简单表示了组播的原理
  • Golang连接Jenkins获取Job Build状态及相关信息

    文章目录 1 连接Jenkins 2 controller 3 module 4 router 5 效果展示 第三方包 gojenkins 方法文档 gojenkins docs 实现起来很简单 利用第三方库 连接jenkins 调用相关方
  • flutter解决键盘顶起页面

    前言 flutter中解决键盘顶起页面的问题 flutter 1 Scaffold resizeToAvoidBottomPadding return Scaffold resizeToAvoidBottomPadding false 解决
  • 使用OpenCV与深度学习从视频和图像中精准识别人脸: Python实践指南

    第一部分 引言与背景 人脸识别已经成为了当代技术领域中最热门和广泛应用的话题之一 从智能手机的解锁功能到机场的安全检查 人脸识别技术无处不在 在这篇文章中 我们将使用Python中的OpenCV库和深度学习模型 深入探讨如何从视频和图像中精
  • js 对数组对象进行排序

    let listData id 1 name 测试1 presenttime 1557883600000 id 2 name 测试2 presenttime 1580751813000 id 3 presenttime 1561448381
  • svn版本号,命令中-r 2和@2的区别

    问题 假设有一个svn repository是 svn 192 168 2 6 project 在版本1 20的svn里 存在 svn 192 168 2 6 project branches branch test 在版本21时 由于br
  • BUUCTF-Web-命令执行-[ACTF2020 新生赛]Exec

    BUUCTF Web 命令执行 ACTF2020 新生赛 Exec 题目链接 BUUCTF 类型 命令注入 知识点 命令拼接符 解题过程 这道题目比较简单 打开发现是一个ping命令执行页面 使用post接受参数 测试命令拼接符 发现未进行
  • CMW500测试设置及问题处理

    测试CATM1需要打开eMTC Auto Mode 最新的U BLOX R510S模块 这里需要设置为RMC模式 设置为eMTC Auto Mode会出现连接后就断开的情况 没法测试 Measure subframe设置为5 不同的band
  • Kubernetes生产实践系列之三十一:Kubernetes基础技术之CPU资源的调度和管理(CFS)

    一 前言 在使用Kubernetes的过程中 我们看到过这样一个告警信息 K8S 告警主题 CPUThrottlingHigh 告警级别 warning 告警类型 CPUThrottlingHigh 故障实例 告警详情 27 throttl
  • android bluetooth UUID蓝牙查询表

    UUID是 Universally Unique Identifier 的简称 通用唯一识别码的意思 对于蓝牙设备 每个服务都有通用 独立 唯一的UUID与之对应 也就是说 在同一时间 同一地点 不可能有两个相同的UUID标识的不同服务 以
  • .Net C# 使用 IKVM 调用 Java 代码

    相关开源库 https github com ikvm revived 版本号 Net 6 JDK 8 IKVM 8 2 1 IKVM 在 8 2 0 版本中新增加 IkvmReference 在 MSBuild 中配置 自动帮你编译jar
  • 虚拟机打开vim文件以后退出方式

    如果是vi 则 Esc 退出编辑模式 输入以下命令 wq 保存后退出vi 若为 wq 则为强制储存后退出 常用 w 保存但不退出 常用 w 若文件属性为 只读 时 强制写入该档案 q 离开 vi 常用 q 若曾修改过档案 又不想储存 使用
  • python制作查询工具发给别人使用_Python 制作查询商品历史价格的小工具

    一年一度的双十一就快到了 各种砍价 盖楼 挖现金的口令将在未来一个月内充斥朋友圈 微信群中 玩过多次双十一活动的小编表示一顿操作猛如虎 一看结果2毛5 浪费时间不说而且未必得到真正的优惠 双十一电商的 明降暗升 已经是默认的潜规则了 打破这
  • 为何在新建STM工程中全局声明两个宏

    在uVision中新建STM32工程后 需要从STM32标准库中拷贝标准外设驱动到自己的工程目录中 此时需要在工程设置 gt C C 选项卡下的Define文本框中键入这两个全局宏定义 STM32F40 41xxx USE STDPERIP
  • 二叉树的一些练习题

    前言 二叉树的简单题目 通过画栈帧图去理解过程 画一画 走一走递归过程 理解会更加深刻 二叉树练习题 前言 二叉树的创建 二叉树先序遍历创建 PreCreat 二叉树层次创建 LevelCreat 二叉树的销毁 BinaryTreeDest
  • 二分法查找数组元素

    二分法查找元素时可以节省下极高的效率 如果有2的32次方个元素 依次查找需要查找2的32次方次 然而二分查找最多只用查找32次 程序执行的时间极大的缩短 二分法查找元素 include
  • nginx中location里面的try_files配置导致Vue设置history模式下的请求丢失参数

    nginx中location里面的try files配置导致vue设置history模式下的请求丢失参数 背景描述 在一次生产环境中 vue使用history模式在访问地址的参数会丢失 地址栏也会变成没有参数的地址 并且请求会发生301重定
  • 快速排序算法详解(原理,时间复杂度,实现代码)

    快速排序算法详解 原理 实现和时间复杂度 快速排序是对冒泡排序的一种改进 由 C A R Hoare Charles Antony Richard Hoare 东尼 霍尔 在 1962 年提出 快速排序的基本思想是 通过一趟排序将要排序的数
  • sql 字段求和_VBA+SQL-常用函数

    SQL语句中的一些简单计算函数 如max函数 SELECT MAX 列字段 AS 别名1 FROM 工作表名 如AVG函数 SELECT AVG 列字段 AS 别名1 FROM 工作表名 使用实例说明 源数据 查询内容 对英语成绩最高分 对
  • 【Java基础】day13

    day13 一 Spring Bean 生命周期是怎样的 详细过程分为以下几个步骤 初始化 Bean 容器通过获取 BeanDefinition 中的信息进行实例化 这一步仅仅是简单的实例化 并没有进行依赖注入 实例化的对象被包装在 Bea