Spring(下)

news2024/11/14 12:41:56

接上篇,从第八个问题讲起

八.Spring工厂创建复杂对象

1.什么是复杂对象

简单对象就是可以直接new出来的,也就是直接调用构造方法创建

所以复杂对象就是不能直接通过调用构造方法创建。就比如JDBC中的Connection

2.三种方法

(1).FactoryBean接口

首先准备一个类,实现上述接口,进行文件配置。里面有三个方法:

getObject方法是用于书写创建复杂对象的代码,并将复杂对象作为方法返回值返回

getObjectType方法是返回复杂对象的class对象

isSingleton方法:若该对象只需创建一次(就是说每次都是用同一个对象),就让这个方法返回true;若每次使用都要创建一个新的对象,就让它返回false。

示例:

我们拿数据库建立连接来举例。既然要使用数据库,我们就要先引入数据库的依赖。

首先来实现getObject方法

其次就是getObjectType方法:

最后就是isSingleton方法

进行文件配置:

获取连接对象:

如上,虽然在配置文件中指定的是FactoryBean接口的实现类,但是获取到的却是Connection对象!!!这就是为啥要实现factorybean接口,原理会在后面讲到

细节分析:
如果就想获得factoryBean对象

在getbean方法中的conn前面加一个&即可

isSingleton方法

如果返回true,没那么每次创建的对象都是同一个:

如果返回false,则不是同一个:

依赖注入

对于connectionFactoryBean来说,下面几个内容是很重要的,是它所依赖的

所以要对他们进行set注入:

首先设置成成员变量,然后提供set方法,再去配置文件

FactoryBean实现原理

首先根据getBean传入的conn字符串获取对应bean标签的相关信息,

其次使用instanceof判断是否是factorybean的实现类

如果是就去执行重写的getObject方法来获取到connection对象,最后返回对象

总结

FactoryBean是Spring种用于创建复杂对象的方式,也是Spring原生提供的

(2).实例工厂

优势

实例工厂能够避免Spring框架的侵入,避免使用Spring提供的FactoryBean。

实力工厂也可以整合遗留系统

示例

写一个ConnectionFactory类作为遗留系统,

然后再配置文件中进行如下配置:

用到了factory-bean属性和factory-method属性

这样就把遗留系统整合了

(3).静态工厂

将getConnection方法换成静态的

配置文件如上

九.控制对象创建的次数

1.简单对象

在bean标签上加一个scope标签,值为singleton则只能创建一个对象,值为prototype(译为原型)则每次都创建新的对象

scope的值默认为singleton

2.复杂对象

就是使用issingleton方法。如果没有重写这个方法,那就还是默认使用scope属性,并且默认为singleton

3.为啥要控制?

有些对象,比如userDao,就可以被共用,有些不可以

好处:节省不必要的内存浪费

十.对象的生命周期

共分为三个阶段

1.创建阶段

Spring工厂何时创建对象?

当scope为singleton时,就是在Spring工厂创建的同时(也就是new ClassPathXmlApplicationContext)进行对象的创建

当scope为prototype时,就是在获取对象时(getBean方法)进行创建

如何证明?我们在person的无参构造中加一个控制台输出

先指定scope为singleton,调试一下:

这次指定scope为prototype,调试一下:

如上,当执行完创建工厂的代码时,控制台没有creat person的字样,但再往下看:

当执行完getBean方法后,出现了person无参构造这个打印语句

注:若scope为singleton,但还是想在获得对象时进行对象创建

则在bean标签中加一个lazy-init属性并且指定为true

2.初始化阶段:

Spring工厂创建完对象后,会调用初始化方法。该初始化方法是程序员提供,Spring工厂进行调用。那么如何提供初始化方法?有两种方式

方式一:InitializationBean接口

创建一个product类,实现initialization接口,并且实现其中的方法afterPropertiesSet

其实看这个方法的名字就知道,该方法的执行时期就是在property标签的set注入执行完毕后进行

下面进行文件配置:

方式二.在对象中提供普通的初始化方法,不实现接口

文件配置:

结果:

细节分析

若一个对象既实现类InitializationBean接口,又写了自己的初始化方法

那么就是先执行接口的方法,再执行自己的方法

如果还有property标签进行注入

那么就先注入,再初始化

初始化操作的意义

一般用在资源初始化中:数据库,IO,网络等

3.销毁阶段

Spring工厂在销毁之前,会调用对象的销毁方法,完成销毁操作

Spring何时销毁对象?

在调用ctx.close方法之后进行

如何销毁?

程序员定义销毁方法,Spring调用

方式一:实现DisposiableBean接口的destroy方法

文件配置:

效果:

为什么调用不了close方法呢?因为编译阶段不知道ctx的具体类型,不知道是classpathxmlapplicationcontext调用的还是webxmlapplicationcontext调用的,所以要向下转型,进行强制类型转换:

方式二:不实现接口,提供普通的销毁方法

细节分析

注意:销毁操作只适用于scope=singleton

销毁操作主要是指资源释放的操作,比如io,connection等

十一.配置文件参数化

指的是把Spring配置文件中,需要经常进行修改的字符串信息,转移到一个更小的配置文件中。规定此配置文件就是.properties文件。

有需要经常修改的字符串吗?当然有,就比如之前讲到的connection的创建,进行依赖注入,那些信息就很可能要修改(比如要换一个数据库)

1.好处

将进场需要修改的字符串转移到小的配置文件中,更利于修改,在改动的同时不会影响Spring配置文件中的其他内容

2.开发步骤

还是使用connection举例

提供小配置文件

我们创建一个db.properties文件

也是key value模式,key可以随便起名

将Spring配置文件与小配置文件进行整合

context:property-placeholder标签,表示读取小配置文件,location属性定义了小配置文件的路径。其中,classpath是Spring配置文件中特有的关键字,代表了target目录下的classes目录。

maven项目:开发时,java和resource目录是两个目录,但是编译后就合二为一了。如何证明?target目录存放的就是编译后的文件,打开就可以看到classes目录下面就有之前java和resource目录下的所有.class文件

将字符串填充到配置文件中:

"${key}"key就是小配置文件中的key

十二.自定义类型转换器

1.什么是类型转换器

在person类中,id是int类型,而Spring配置文件也是文件,它里面的内容就应该是字符串,那它怎么就把字符串赋值给了int类型呢?这是因为Spring中内置了类型转换器Converter,并且借助接口实现(为啥是接口?因为字符串要转换成不同的类型)

但是像date类型,每个地区的人的习惯性写法不同,所以Spring就可能无法将日期字符串转化成标准的Date格式(后面会讲为什么是可能)。那该怎么办?这就要我们程序员自定义类型转换器了

2.自定义类型转换器

创建一个Converter包,Person类

再写一个converter接口的实现类

Converter是一个泛型接口,见括号中的第一个表示原始类型,第二个表示要转换成什么类型

接下来我们就要去实现convert方法,这个方法的参数就是Spring配置文件中要被转换的那个字符串

最后在Spring配置文件中配置

首先要将自己写的类型转换器创建出来,然后要在Spring中进行注册。如何注册?

Spring中提供了一个类ConverterFactoryBean,它里面存放的就是各种类型转换器,是以Set集合存储的

所以要想使用自己的类型转换器,就要将自己写的类型转换器存放到set集合中,就如上所示。这样,就能将字符串转化成Date类型啦

3.细节分析

yyyy-MM-dd

它是MydateConverter的依赖项,所以可以对它进行依赖注入,也就是将它作为成员变量进行配置,后需要想修改格式,只需要修改Spring文件即可,就不用重新编译部署,就可以解耦合

为ConverterFactoryBean设标签

要注意id值必须为converterService,否则注册类型转换器不成功

Spring其实内置了日期的类型转换器

但它要求日期格式必须为:四位/二位/二位,否则无法自动转换

十三.后置处理bean

1.Spring创建对象的流程

1.反射调用构造方法

2.DI(注入)

3.InitializingBean的afterPropertySet方法对对象进行初始化

4.init-method="myInit",自定义的初始化方法

学到这里,我们就要再加一个BeanPostProcessor接口,他就是对Spring工厂所创建的对象进行再加工(就像苹果从果园中生长出来后没有直接到顾客手里,而是进行了再加工,提高了品质)

该接口中有两个方法

一个是Before,表示在调用InitializingBean接口的方法之前进行,一个是After,表示在调用了自定义的初始化方法之后进行

2.开发步骤

我们准备一个beanPost包和Category类

进行文件配置:

然后创建一个MyBeanPostProcessor类,实现BeanPostProcessor接口

我们没有实现这两个方法,但是没有报错,这是因为这两个方法是default,表示接口的默认实现

我们的目的是将name属性从小红改为小明。那该如何实现这两个方法呢?如下:

在实际开发中,很少会进行初始化操作,所以上面这两个方法实现一个即可,一般是实现after方法,另一个就返回bean。

最后进行文件配置

效果:

运行后竟然报错了!这是我们之前写的类型转换器不能转换成Category类。这是啥错误?

仔细看这个配置文件,里面有好多个bean标签,最后一个bean标签就是在创建beanPostProcessor的实现类,事实上,同一个配置文件中的对象都要调用BeanPostProcessor接口的方法,即下面我们重写的这个方法:

注意这个bean,这个bean可不是单单是Category对象,而将会是同一个配置文件中的所有对象,所以在话蓝线的这一句就会出现类型转换异常。那么该如何解决此问题?如下:

首先用instanceof判断一下是否是Category类,如果是才能进行下面的修改操作,不是就直接返回,返回的时候也是直接返回bean对象即可

所以一定要注意:​​​​​​​beanPostProcessor会对Spring文件中的所有对象进行加工,所以一定要进行类型匹配的判断。

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

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

相关文章

【LeetCode刷题记录】206. 反转链表

206 反转链表 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入:head [1,2] 输出:[2,1] 示例…

毕业设计——基于ESP32的智能家居系统(语音识别、APP控制)

ESP32嵌入式单片机实战项目 一、功能演示二、项目介绍1、功能演示2、外设介绍 三、资料获取 一、功能演示 多种控制方式 ① 语音控制 ②APP控制 ③本地按键控制 ESP32嵌入式单片机实战项目演示 二、项目介绍 1、功能演示 这一个基于esp32c3的智能家居控制系统,能实…

MyCat 数据库中间件

一、介绍 1、单数据库进行数据存储的问题: IO瓶颈:热点数据太多,数据库缓存不足以容纳这些热点数据,产生大量磁盘IO,效率较低。 CPU瓶颈:排序、分组、连接查询、聚合统计等SQL会耗费大量的CPU资源。 2、…

Rest接口/Nginx日志记录和采集

文章目录 一、Rest接口日志二、Nginx日志三、采集日志四、夜莺查看Nginx日志五、夜莺查看Rest接口日志 一、Rest接口日志 记录日志字典定义 接口URL接口名称,类别,入参全记录,出参全记录,入参字段1:中文名1/入参字段2:中文名2,出参字段1:中文名1/test/api/login账户登录,登录…

【C++】开始使用优先队列

送给大家一句话: 这世上本来就没有童话,微小的获得都需要付出莫大的努力。 – 简蔓 《巧克力色微凉青春》 开始使用优先队列 1 前言2 优先队列2.1 什么是优先队列2.2 使用手册2.3 仿函数 3 优先队列的实现3.1 基本框架3.2 插入操作3.3 删除操作3.4 其他函数 4 总结T…

kubernetes的网络通信实现原理

网络原理 Kubernetes网络原理详解:一、Kubernetes 网络实现1.容器到容器(同一Pod内)通信流程:2. pod之间的通信(以Calico为例): 二、CNI 网络模型三、网络策略四、开源的容器网络方案五、 常见网…

Linux管道共享内存

前言 进程虽然是独立运行的个体,但它们之间有时候需要协作才能完成一项工作,比如有两个进程需要同步数据,进程 A 把数据准备好后,想把数据发往进程 B,进程 B 必须被提前通知有数据即将到来,或者进程 A 想发…

Spark集群的搭建

1.1搭建Spark集群 Spark集群环境可分为单机版环境、单机伪分布式环境和完全分布式环境。本节任务是学习如何搭建不同模式的Spark集群,并查看Spark的服务监控。读者可从官网下载Spark安装包,本文使用的是spark-2.0.0-bin-hadoop2.7.gz。 1.1.1搭建单机版…

《乱弹篇(30)厌战的杜诗》

时下地球村有一伙成天叫嚣着“打打杀杀”、鼓吹快快发动战争的狂人,他们视老百姓的生命如草芥,毫不珍惜。没有遭受过战火焚烧的人,也跟着成天吠叫“快开战吧”。然而中国唐朝大诗人却是个“厌战派”,他对战争的厌恶集中表现在诗《…

实在RPA设计器试用导引

一、产品概述 实在RPA设计器是一款将人工智能(AI)与机器人流程自动化(RPA)深度融合的可视化自动流程编辑器。它通过AI推荐与桌面嵌入式交互,极大简化了RPA的使用难度,让普通业务人员也能轻松使用。实在RPA设计器具备以下核心优势: 兼容性&a…

我与C++的爱恋:类和对象(四)

​ ​ 🔥个人主页:guoguoqiang. 🔥专栏:我与C的爱恋 ​ 朋友们大家好!本篇是类和对象的最后一个部分。 一、static成员 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之…

系统架构最佳实践 -- 相关JAVA架构

1. java 类加载器架构 2. JVM 架构 3. Java 技术体系 4. 线程运行架构 5. Java 体系(编译与运行)结构 6. JMS 技术架构 7. JMX 技术架构 8. Spring 架构 9. Hibernate 架构 10. ibatis 架构 11. Struts2 架构 12. Struts1 架构 13. JBPM 14. EJB 技术架构…

Java面试八股之marshalling和demarshalling

marshalling和demarshalling Marshalling(序列化)是将内存中的对象状态转化为适合传输或存储的格式(如字节流、JSON、XML),以便进行网络通信、持久化存储或跨平台/语言交互操作。Demarshalling(反序列化&a…

渗透测试入门教程,从零基础入门到精通(非常详细)

目录 什么是渗透测试 渗透测试的重要性 渗透测试的前置技能 开始入门学习路线 什么是渗透测试 渗透测试,通常被视为模拟黑客的一种安全评估行为,其目的在于全面挖掘目标网站或主机的潜在安全漏洞。与真实的黑客攻击不同,渗透测试旨在发现…

9.MMD 基础内容总结及制作成品流程

前期准备 1. 导入场景和模型 在左上角菜单栏,显示里将编辑模型时保持相机和光照勾选上,有助于后期调色 将抗锯齿和各向异性过滤勾掉,可以节省资源,避免bug 在分辨率设定窗口,可以调整分辨率 3840x2160 4k分辨率 1…

05 MySQL--字段约束、事务、视图

1. CONSTRAINT 约束 创建表时,可以给表的字段添加约束,可以保证数据的完整性、有效性。比如大家上网注册用户时常见的:用户名不能为空。对不起,用户名已存在。等提示信息。 约束包括: 非空约束:not null检…

kafka实验部署

一、前期准备 二、kafka实验 在zookeeper后继续进行操作 2.1 为ndoe1、node2、node3作出部署 2.1.1 解压kafka压缩包(node1举例) 2.1.2 操作 将解压后的kafka移动到kafka,进入到kafka下的config中,复制文件 2.1.2.1 编辑server.pr…

LWIP开发之静态IP为什么接收和发送不了数据

使用的硬件开发板是探索者F4 V3版本 这里用的LWIP的lwIP例程7 lwIP_NETCONN_UDP实验 问了开发板的官方和其他人都说不清楚;搞了两天,浪费了两天时间; 最奇葩的问题还在于只能单片机发送,上位机能接收。而上位机发送单片机不能接…

虚拟机扩容方法

概述 我的虚拟机开始的内存是40G,接下来要扩成60GB 扩容步骤 步骤1 步骤2 步骤3 修改扩容后的磁盘大小,修改后的值只可以比原来的大,修改完成后点击扩展,等待扩展完成 步骤4 虽然外面扩展成功,但是新增的磁盘空间虚拟机内部还…

自媒体个人品牌IP策划打造孵化运营方案

【干货资料持续更新,以防走丢】 自媒体个人品牌IP策划打造孵化运营方案 部分资料预览 资料部分是网络整理,仅供学习参考。 ppt可编辑(完整资料包含以下内容)目录个人IP孵化方案概要: 1. 目标定位与市场分析 - 女性…