Spring03——基于xml的Spring应用
Spring开发中主要对Bean的配置
Bean的常用配置一览如下:
Xml配置方式 | 功能描述 |
---|---|
<bean id="" class=""> | Bean的id和全限定名配置 |
<bean name=""> | 通过name设置Bean的别名,通过别名也能直接获取到Bean实例 |
<bean scope=""> | Bean的作用范围,BeanFactory作为容器时取值singleton和prototype |
<bean lazy-init=""> | Bean的实例化时机,是否延迟加载。BeanFactory作为容器时无效 |
<bean init-method=""> | Bean实例化后自动执行的初始化方法,method指定方法名 |
<bean destroy-method=""> | Bean实例销毁前的方法,method指定方法名 |
<bean autowire="byType"> | 设定自动注入模式,常用的有按类型byType,按名称byName |
<bean factory-bean="" factory-method=""/> | 指定哪个工厂Bean的哪个方法来完成Bean的创建 |
Bean取别名
通过name取别名,同样可以获取实例
Bean的范围配置
默认情况下,单纯的Spring环境Bean的作用范围有两个(scope配置):Singleton和Prototype
- singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例;
- prototype(默认):原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。
Bean的延迟加载
当lazy-init设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时在创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单例的
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" lazy-init="true"/>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// lazy-init="true"开启,那么只有调用getBean时才会创建Bean实例,而不是之前创建容器时UserService userService = (UserService) applicationContext.getBean("aaa");System.out.println(userService);
Bean的初始化和销毁方法配置
Bean在被实例化后,可以通过指定的初始化方法完成一些初始化的操作,Bean在销毁之前也可以执行指定的销毁方法完成一些操作。
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"init-method="init" destroy-method="destroy"/>
定义init方法和destory方法
public class UserDaoImpl implements UserDao { public UserDaoImpl() { System.out.println("UserDaoImpl创建了..."); } public void init() { System.out.println("初始化方法..."); } public void destroy() { System.out.println("销毁方法..."); }
}
由上图可见,并没有显示销毁方法
关闭容器Bean就销毁,否则bean销毁不了,因为关闭容器是在虚拟机结束之前执行,如果没有close,那么虚拟机关闭,什么都没有了。
扩展:除此之外,我们还可以通过实现 InitializingBean 接口,完成一些Bean的初始化操作,如下:
public class UserDaoImpl implements UserDao, InitializingBean { public UserDaoImpl() { System.out.println("UserDaoImpl创建了..."); } public void init() { System.out.println("初始化方法..."); } public void destroy() { System.out.println("销毁方法..."); } // 执行时机早于init-method配置的方法 @Overridepublic void afterPropertiesSet() throws Exception { System.out.println("InitializingBean..."); }
}
使用InitializingBean , DisposableBean接口(推荐)
这样就不需要再Bean标签里写init和destory了
Bean的生命周期
下面是Spring Bean生命周期示例,包括创建、初始化和销毁的代码。
Bean类
创建一个简单的Bean类,并定义初始化和销毁方法:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.DisposableBean; public class MyBean implements InitializingBean, DisposableBean { private String name; private String version; private String author; public MyBean() { System.out.println("1. 创建对象 - 构造器"); } public void setName(String name) { this.name = name; System.out.println("设置属性 - name: " + name); } public void setVersion(String version) { this.version = version; System.out.println("设置属性 - version: " + version); } public void setAuthor(String author) { this.author = author; System.out.println("设置属性 - author: " + author); } @Override public void afterPropertiesSet() throws Exception { System.out.println("4. 执行Bean初始化方法 (afterPropertiesSet)"); System.out.println("Bean 信息 - Name: " + name + ", Version: " + version + ", Author: " + author); } @Override public void destroy() throws Exception { System.out.println("关停 Bean - 销毁方法 (destroy)"); } public void performTask() { System.out.println("执行业务操作 - " + name); }
}
Spring配置
使用XML配置来定义Bean,指定其由接口管理的初始化和销毁方法:
<bean id="myBean" class="com.example.MyBean"> <property name="name" value="Spring Bean"/> <property name="version" value="1.0"/> <property name="author" value="John Doe"/> </bean>
主程序
创建Application
类,加载Spring上下文,使用Bean并关闭上下文以触发销毁阶段:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); MyBean myBean = (MyBean) context.getBean("myBean"); // 执行myBean的一些业务// 关闭上下文,触发销毁方法 ((ClassPathXmlApplicationContext) context).close(); }
}
Bean的3种实例化
构造方式实例化:底层通过构造方法对Bean进行实例化
工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化
Bean的实例化配置
构造方式实例化Bean又分为无参构造方法实例化和有参构造方法实例化,Spring中配置的<bean>
几乎都是无参构造方式,但处不在赘述。下面讲解有参构造方法实例化Bean
// 有参构造方法
public UserDaoImpl(String name){
}
在实现类文件里默认有一个无参构造器,如果写一个有参构造器,那么jvm识别不到无参构造器会报错 。
在实现类文件中写入有参构造方法后,有参构造在实例化Bean时,需要参数的注入,通过<constructor-arg>
标签(name表示传入的变量名,value表示变量名对应的传入参数,在bean标签里传入即可,调用getBean会自动添加进去,如果有多个参数,就多个<constructor-arg>标签
),嵌入在<bean>
标签内部提供构造参数,如下:
<!--上面的有参构造器对应的xml配置-->
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"> <constructor-arg name="name" value="haohao"/>
</bean>
静态工厂创建对象
factory-method 创建对象:即在xml的bean标签里配置factory-method = "userDao",那么创建getBean对象返回的不是class对应的类的实例,而是class类里面userDao静态方法返回的实例
<bean id="userDao1" class="com.itheima.factory.MyBeanFactory1"factory-method="userDao"></bean>
public class MyBeanFactory1 {public static UserDao userDao(){// bean之前可以进行其他的业务逻辑操作return new UserDaoImpl();}
}
实例工厂创建对象
<--实例化一个工厂-->
<bean id="myBeanFactory2" class="com.itheima.factory.MyBeanFactory2"lazy-init="true"></bean>
<--factory-bean是代指工厂-->
<bean id="userDao2" factory-bean="myBeanFactory2"
factory-method="userDao" lazy-init="true"></bean>
public class MyBeanFactory2 {
// 实例方法返回对象public UserDao userDao(){return new UserDaoImpl();}
}
FactoryBean创建(实用)
package com.itheima.factory;import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;public class UserDaoFactoryBean implements FactoryBean {// 返回bean@Overridepublic UserDao getObject() throws Exception {return new UserDaoImpl();}// 返回Bean的类型@Overridepublic Class<?> getObjectType() {return UserDao.class;}
// 是否为单例@Overridepublic boolean isSingleton() {return true;}
}
<bean id="UserDao" class="com.itheima.factory.UserDaoFactoryBean"></bean>
依赖注入的方式
一、setter方法注入引用类型/简单类型(下面以同时注入这两种类型为例)
假设我们有一个Product
类,它包含一个简单类型属性(如productId
)和一个引用类型属性(如Category
)。
1. 定义Category
类
首先,定义Category
类,表示产品类别:
public class Category { private String categoryName; // Setter方法 public void setCategoryName(String categoryName) { this.categoryName = categoryName; } // Getter方法 public String getCategoryName() { return categoryName; } public void displayInfo() { System.out.println("Category: " + categoryName); }
}
2. 定义Product
类
接下来,定义一个Product
类,它具有一个简单类型的productId
和一个引用类型的Category
:
public class Product { private String productId; // 简单类型 private Category category; // 引用类型 // Setter方法注入 public void setProductId(String productId) { this.productId = productId; } public void setCategory(Category category) { this.category = category; } public void displayProductInfo() { System.out.println("Product ID: " + productId); if (category != null) { category.displayInfo(); } else { System.out.println("No category information available."); } }
}
3. Spring配置文件
在Spring的XML配置文件中,定义Category
和Product
的Bean,并同时注入简单类型和引用类型:
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="category" class="com.example.Category"> <property name="categoryName" value="Electronics"/> <!-- 注入简单类型 --> </bean> <bean id="product" class="com.example.Product"> <property name="productId" value="P12345"/> <!-- 注入简单类型name是形参 --> <property name="category" ref="category"/> <!-- 注入引用类型 --> </bean>
</beans>
4. 主程序
最后,创建一个主程序,通过Spring上下文来获取Product
对象并执行相应操作:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { // 加载Spring上下文 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 获取product Bean Product product = (Product) context.getBean("product"); product.displayProductInfo(); // 显示产品信息 // 关闭上下文 ((ClassPathXmlApplicationContext) context).close(); }
}
运行结果
运行程序将输出以下内容:
Product ID: P12345
Category: Electronics
二、构造器注入引用类型/简单类型(下面以同时注入这两种类型为例)
1. 定义Category
类
Category
类保持不变,依然表示产品类别
2. 定义Product
类
将Product
类的构造函数修改为接收两个参数:一个简单类型productId
和一个引用类型Category
。
public class Product { private String productId; // 简单类型 private Category category; // 引用类型 // 构造函数注入 public Product(String productId, Category category) { this.productId = productId; this.category = category; } public void displayProductInfo() { System.out.println("Product ID: " + productId); if (category != null) { category.displayInfo(); } else { System.out.println("No category information available."); } }
}
3. Spring配置文件
在Spring的XML配置文件中,使用构造器来注入简单类型和引用类型。我们可以使用constructor-arg
来指定构造函数参数:
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="category" class="com.example.Category"> <property name="categoryName" value="Electronics"/> <!-- 注入简单类型 --> </bean> <bean id="product" class="com.example.Product"> <constructor-arg value="P12345"/> <!-- 注入简单类型 --> <constructor-arg ref="category"/> <!-- 注入引用类型 --> </bean>
</beans>
4. 主程序
主程序实例保持不变,只是调用已经不同的注入手段(构造器)来获取Product
对象并执行操作
- 强制依赖使用构造器进行,使用setter注入有概率不进行时导致null对象出现
- 可选依赖使用setter注入进行,灵活性强
- Spring框架倡导使用构造器,第三方框架内部多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以同时使用,使用构造器注入完全依赖的注入,使用setter注入完成可选依赖的注入
- 实际开发过程中需要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- 自己开发的模块推荐使用setter注入
依赖自动装配
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配时(byType)必须保证容器中相同类型的bean唯一,推荐使用
- 使用按名称装配时(byName)必须保证容器中具有指定名称的bean,因为变量名与配置混合,不推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
集合的注入
<!-- 定义一个bean,id为bookDao,对应的实现类为com.itheima.dao.impl.BookDaoImpl -->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"><!-- 配置一个名为array的属性,类型为数组 --><property name="array"><!-- 数组元素 --><array><!-- 数组中的值 --><value>100</value><value>200</value><value>300</value></array></property><!-- 配置一个名为list的属性,类型为列表 --><property name="list"><!-- 列表元素 --><list><!-- 列表中的值 --><value>itcast</value><value>itheima</value><value>boxuegu</value><value>chuanzhihui</value></list></property><!-- 配置一个名为set的属性,类型为集合 --><property name="set"><!-- 集合元素 --><set><!-- 集合中的值,注意集合不允许重复值 --><value>itcast</value><value>itheima</value><value>boxuegu</value><!-- 重复的值boxuegu将被忽略 --><value>boxuegu</value></set></property><!-- 配置一个名为map的属性,类型为映射 --><property name="map"><!-- 映射元素 --><map><!-- 映射中的键值对 --><entry key="country" value="china"/><!-- 可以继续添加更多的键值对 --></map></property>
</bean>
相关文章:

Spring03——基于xml的Spring应用
Spring开发中主要对Bean的配置 Bean的常用配置一览如下: Xml配置方式功能描述<bean id"" class"">Bean的id和全限定名配置<bean name"">通过name设置Bean的别名,通过别名也能直接获取到Bean实例<bean sc…...
【AIGC半月报】AIGC大模型启元:2024.12(上)
【AIGC半月报】AIGC大模型启元:2024.12(上) (1)OpenAI-12日发布会(持续更新中........)Day01-12.06:SoraDay02-12.07:ChatGPT圣诞老人风格的语音Day03-12.08:…...
本etcd系列文章补充说明
最开始今年四月份读的是etcdv3.6的main分支的代码,最开始没注意,main分支代码是不断修改的,并且最开始对etcd不太了解,所以源码笔记有些理解不太准确,也可能略有错误,所以年底就回过头来重新复习一遍&#…...

【新品发布】ESP32-P4开发板 —— 启明智显匠心之作,为物联网及HMI产品注入强劲动力
核心亮点: ESP32-P4开发板,是启明智显精心打造的一款高性能物联网开发板。它专为物联网项目及HMI(人机界面)产品而设计,旨在为您提供卓越的性能和稳定可靠的运行体验。 强大硬件配置: 双核400MHz RISC-V处…...

HTML 添加 文本水印
body,html {margin: 0;height: 100vh;width: 100vw;} // 自定义文案const setting {text: "水印文案", // 水印内容innerDate: true, // 在水印下方增加日期width: 110, // 水印宽度};// 自定义文字水印const watermark (function () {return {build: function (a…...

软件无线电安全之GNU Radio基础(下)
往期回顾 软件无线电安全之GUN Radio基础(上) 背景 在上一小节中,我们简单介绍和使用了GNU Radio软件的基础功能和模块,同时通过GNU Radio Companion(GRC)创建了简单的流程图,展示了信号生成、处理和输出的流程。最后…...
windows基础
系统目录 服务 端口 注册表 黑客常用DOS命令(在拿到shell时会用到) 一、 系统目录 Windows目录 系统的安装目录 System32configSAM文件 是用户密码的存储文件 System32etchost文件 记录本地解析(优先级大于DNS域名解析)可以自…...

hhdb数据库介绍(10-43)
安全 密码安全管理 密码安全管理为用户提供了对计算节点数据库用户与存储节点的连接用户、备份用户的密码有效期监控提醒。到期后自动提示用户修改密码以提升系统的安全性。 数据库用户密码 (一)密码修改 用户可以在“安全->密码安全管理->数据…...
JMS和消息中间件:Kafka/RocketMQ
文章目录 消息传递模型使用JMS还是KafkaKafka与RocketMQ的优缺点Kafka与RocketMQ的使用场景Kafka与RocketMQ的选型指南 TPM 项目中, iflow之间使用了JMS,后端项目与数据库通信使用Kafka MQ和JMS的区别: JMS是 java 用来处理消息的一个API规范…...

【问题解决】ArcgisGP工具使用GIS模块自动发布图层报错:过渡失败
项目场景: 使用Arcpy脚本发布GP工具服务,该工具结果生成一个矢量文件,并且需要自动发布成在线图层,脚本中已经包含了自动发布图层的代码,本地在ArcgisPro中执行成功。现在需要将该工具发布成web工具。 问题描述 在…...
Yocto bitbake and codeSonar
1 mdm 1.1 屏蔽mdm sysvinit的console输出 - uboot传入参数的时候传入consolenull,这样Linux启动信息没有了 - 还需要在Linux配置中去掉Support for console on AMBA serial port - 文件系统/etc/inittab文件里注释掉::respawn:/sbin/getty -L ttyS000 115200 vt100…...

gpt-computer-assistant - 极简的 GPT-4o 客户端
更多AI开源软件: AI开源 - 小众AIhttps://www.aiinn.cn/sources gpt-computer-assistant是一个将 ChatGPT MacOS 应用程序提供给 Windows 和 Linux 的替代工作。因此,这是一个全新且稳定的项目。此时,您可以轻松地将其作为 Python 库安装&am…...

中国移动量子云平台:算力并网590量子比特!
在技术革新的浪潮中,量子计算以其独特的并行处理能力和指数级增长的计算潜力,有望成为未来技术范式变革和颠覆式创新应用的新源泉。中国移动作为通信行业的领军企业,致力于量子计算技术研究,推动量子计算产业的跨越式发展。 量子云…...
Vue 3 中的计算属性(Computed Properties)详解
目录 Vue 3 中的计算属性(Computed Properties)详解 引言 什么是计算属性? 创建和使用计算属性 示例 1:基本用法 示例 2:带有 getter 和 setter 的计算属性 计算属性 vs 方法 Vue 3 中的计算属性(Co…...
AWS S3 权限配置与文件上传下载指南
本文介绍如何配置 AWS S3 存储桶的访问权限,实现 EC2 实例上传文件和本地用户下载文件的功能。 权限配置 © ivwdcwso (ID: u012172506) 1. EC2 角色上传权限 创建 IAM 角色并附加以下策略,允许 EC2 实例上传文件到 S3: {"Version": "2012-10-17&qu…...

6. 一分钟读懂“抽象工厂模式”
6.1 模式介绍 书接上文,工厂方法模式只能搞定单一产品族,遇到需要生产多个产品族时就歇菜了。于是,在需求的“花式鞭策”下,程序员们再次绷紧脑细胞,创造出了更强大的抽象工厂模式,让工厂一次性打包多个产品…...

CV(2)-插值和卷积
前言 仅记录学习过程,有问题欢迎讨论 看看年前可以学到哪。 频率: 灰度值变化程度的指标,是灰度再平面上的梯度幅值: 幅值: 是在一个周期内,交流电瞬时出现的最大绝对值,也是一个正弦波,波…...

学习threejs,通过设置纹理属性来修改纹理贴图的位置和大小
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️Texture 贴图 二、…...

fastadmin 后台插件制作方法
目录 一:开发流程 二:开发过程 (一):后台功能开发 (二):功能打包到插件目录 (三):打包插件 (四):安装插件…...

9. 一分钟读懂“策略模式”
9.1 模式介绍 策略模式是一种行为型设计模式,用于在运行时灵活切换对象的行为或算法,它将算法封装为独立的类,使得它们可以互相替换,而不会影响使用这些算法的客户端代码。 策略模式的核心思想是:定义一系列可互换的算…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...