对Spring源码的学习:基于XML文件配置的开发流程

目录

BeanFactory开发流程

ApplicationContext

BeanFactory与ApplicationContext对比

基于XML方式的Bean的配置

自动装配


BeanFactory开发流程

这里的第三方指的是Spring提供的BeanFactory,Spring启动时会初始化BeanFactory,然后读取配置清单(xml文件)获取需要被加载的bean。实现上面流程图的具体代码如下

创建beans.xml文件

public class Test {public static void main(String[] args) {//定义出一个bean工厂DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//读取xml文件的读取器XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);//读取配置文件reader.loadBeanDefinitions("beans.xml");UserService userService = (UserService) beanFactory.getBean("userService");System.out.println(userService);}
}

因为我们在开发中要遵循三层架构,业务层需要定义数据层,那么接下来我们再在xml文件中指定要一个数据层bean。代码如下

public class UserServiceImpl implements UserService {//该方法由beanFactory来调用,set注入public void setUserDao(UserDao userDao){System.out.println("由bean工厂调用该set方法");}
}

需要注意的是,需要property标签中的属性的name应该是setXxx()方法中的Xxx第一个子母小写之后的字符,ref标签指的是bean定义的id。接下来我们查看Test类的运行结果

public class Test {public static void main(String[] args) {//定义出一个bean工厂DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//读取xml文件的读取器XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);//读取配置文件reader.loadBeanDefinitions("beans.xml");UserService userService = (UserService) beanFactory.getBean("userService");}
}

执行结果截图 

BeanFactory是Spring中最重要的核心类,下文中的ApplicationContext虽然叫做Spring容器,但实际上在该类中最后调用的还是BeanFactory。

ApplicationContext

ApplicationContext称为Spring容器,内部封装了BeanFactory,比BeanFactory功能更丰富,使用ApplicationContext时,xml文件配置我们习惯叫做applicationContext.xml。接下来是一个示例代码

public class ApplicationContextTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Object userService = context.getBean("userService");}
}

BeanFactory与ApplicationContext对比

  1. BeanFactory是Spring的早期接口,称为Spring的Bean工厂,ApplicationContext是后期更高级接口,称之为Spring 容器
  2. ApplicationContext在BeanFactory基础上对功能进行了扩展,例如: 监听功能、国际化功能等。BeanFactory的API更偏向底层,ApplicationContext的API大多数是对这些底层API的封装;
  3. Bean创建的主要逻辑和功能都被封装在BeanFactory中ApplicationContext不仅继承了BeanFactory,而且ApplicationContext内部还维护着BeanFactory的引用,所以,ApplicationContext与BeanFactory既有继承关系,又有融合关系。
  4. Bean的初始化时机不同,原始BeanFactory是在首次调用getBean时才进行Bean的创建,而ApplicationContext则是配置文件加载,容器一创建就将Bean都实例化并初始化好

基于XML方式的Bean的配置

XmI配置方式

功能描述

<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的创建

默认情况下,单纯的Spring环境的Bean的作用范围有两个:Singleton与Prototype

  • Singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例。
  • Prototype:原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。

Spring实例化Bean的两种方式如下:

一:通过构造方法实例化

默认在xml文件中配置的信息都是调用了无参构造器,但是如果我们需要参数时,需要添加constructor-arg标签,该标签标识向方法中传递参数。

<beans><bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><!-- 默认采用无参构造器,但如果需要参数,则需要进行配置 --><constructor-arg name="参数名称" value="参数值"></constructor-arg><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>

二:通过调用自定义的工厂方法对Bean进行实例化

静态工厂方法实例化Bean

public class MyBeanFactory {public static UserDao getUserDao(){//在实例化Bean之前,我们可以进行一些业务逻辑操作return new UserDaoImpl();}
}
  <beans><!--指定执行自定义的Bean工厂的指定方法去实例化Bean--><bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean><bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean></beans>

可以看到执行结果,一个是通过无参构造器创建出来的Bean一个是通过自定义的静态工厂创建的。

实例工厂方法实例化Bean

与静态工厂方法实例化Bean区别在于,我们需要将工厂类也加载为Bean对象,然后通过该Bean对象去实例化

public class MyBeanFactory1 {public UserDao getUserDao(){//在实例化Bean之前,我们可以进行一些业务逻辑操作return new UserDaoImpl();}
}
<beans><!--加载工厂Bean--><bean id="myBeanFactory1" class="com.zmt.factory.MyBeanFactory1"></bean><!--通过工厂Bean去获取需要的对象--><bean id="userDao2" factory-bean="myBeanFactory1" factory-method="getUserDao"></bean><!--指定执行自定义的Bean工厂的指定方法去实例化Bean--><bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean><bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>

实现FactoryBean规范延迟实例化Bean

//需要指定FactoryBean的泛型
public class MyBeanFactory2 implements FactoryBean<UserDao> {//该方法在执行getBean的时候去执行@Overridepublic UserDao getObject() throws Exception {return new UserDaoImpl();}//获取该Bean工厂产生的Bean类型@Overridepublic Class<?> getObjectType() {return UserDao.class;}
}
  <beans><!--Bean名称是userDao3,但加载的是工厂类--><bean id="userDao3" class="com.zmt.factory.MyBeanFactory2"></bean><!--加载工厂Bean--><bean id="myBeanFactory1" class="com.zmt.factory.MyBeanFactory1"></bean><!--通过工厂Bean去获取需要的对象--><bean id="userDao2" factory-bean="myBeanFactory1" factory-method="getUserDao"></bean><!--指定执行自定义的Bean工厂的指定方法去实例化Bean--><bean id="userDao1" class="com.zmt.factory.MyBeanFactory" factory-method="getUserDao"></bean><bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean></beans>

延迟加载Bean实际上是先加载了工厂Bean类,当需要用到Bean时,会从单例池中获取FactoryBean后调用该对象中的getObject()方法获取到真正的的Bean对象,并将该Bean对象缓存在factoryBeanObjectCache中,当使用到该Bean对象时从该Map中获取。

自动装配

我们通过编写property标签进行的注入叫做手动注入,而自动装配是不需要编写property标签的,而是在bean标签中使用autowire属性来实现自动注入,aotuwire的值有两个:byName、byType

  • byName:通过属性名自动装配,去匹配setXxx与id="xxx"是否一致
  • byType:通过Bean的类型从容器中匹配,匹配出多个相同Bean类型时,报错

UserServiceImpl存在一个setUserDao方法,因此我们可以这么编写,同样可以将属性注入到UserServiceImpl中

<beans><bean id="userService" class="com.zmt.service.impl.UserServiceImpl" autowire="byName"></bean><bean id="userDao" class="com.zmt.dao.impl.UserDaoImpl"></bean>
</beans>

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

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

相关文章

2021实战面试

1、Rem , em , px , % , vw 之间的区别 PX: px像素&#xff08;Pixel&#xff09;。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。 em: 1,子元素字体大小的em是相对于父元素字体大小 2,元素的width/height/padding/margin用em的话是相对于该元素的font-size rem:1rem是…

智能优化算法应用:基于象群算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于象群算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于象群算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.象群算法4.实验参数设定5.算法结果6.参考文献7.MA…

仿windows12网盘,私有云盘部署教程,支持多种网盘

仿windows12网盘,私有云盘部署教程&#xff0c;支持多种网盘 资源宝分享&#xff1a;www.httple.net 视频教程&#xff1a;https://www.bilibili.com/video/BV1m64y1G7Bq/ 宝塔部署方式&#xff1a; 1.验证是否安装jdk,没有安装请看安装教程 推荐安装jdk8&#xff08;注意您…

SAP ABAP 面试题交流

1.列举AT事件并说明其作用&#xff0c;AT事件中的工作区有何不同&#xff1f; AT FIRST 循环loop中执行第一条数据 AT LAST 循环loop中执行最后一条数据 AT NEW 循环loop中指定字段&#xff08;包含指定字段&#xff09;记录与上一条记录不一致数据执行 AT END OF 循环loo…

Visual Studio调试技巧合集

Visual Studio调试技巧合集 1 如何同一个项目运行不同main文件&#xff1f; 1 如何同一个项目运行不同main文件&#xff1f; &#xff08;1&#xff09;移动鼠标到需要关掉调试的文件&#xff0c;点击右键属性–常规–从生成中排除–是–确定&#xff0c;即显示“-”号排除&am…

Python自动化测试系列[v1.0.0][多种数据驱动实现附源码]

前情提要 请确保已经熟练掌握元素定位的常用方法及基本支持&#xff0c;请参考Python自动化测试系列[v1.0.0][元素定位] 数据驱动测试是自动化测试中一种重要的设计模式&#xff0c;这种设计模式可以将测试数据和测试代码分开&#xff0c;实现数据与代码解耦&#xff0c;与此同…

变量与方法面试题

char 型变量中能不能存储一个中文汉字&#xff0c;为什么&#xff1f; char 类型可以存储一个中文汉字&#xff0c;因为 Java 中使用的编码是 Unicode&#xff08;不选择任何特定的编码&#xff0c;直接使用字符在字符集中的编号&#xff0c;这是统一的唯一方法&#xff09;&a…

Python FuckIt模块:代码的“不死鸟”

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在编程世界中&#xff0c;每个开发者都曾遇到过代码中的错误&#xff0c;有时这些错误可能让人崩溃。但是&#xff0c;有一天&#xff0c;听说了一个叫做"FuckIt"的模块&#xff0c;它声称可以帮助摆脱…

【PIE-Engine 数据资源】全球海面温度产品

文章目录 一、 简介二、描述三、波段四、示例代码参考资料 一、 简介 数据名称全球海面温度产品时间范围2002年- 2018年空间范围全球数据来源毛克彪教授团队代码片段var images pie.lmageCollection(“CAAS/SSTG”) 二、描述 全球海面温度产品是 2002-2019 年的全球海面温度…

ES中根据主键_id查询记录

一、需求 es中_type&#xff1a;_doc&#xff0c;想要根据主键_id查询记录 二、实现 复合查询中使用语句查询http://192.168.1.1/_doc/1

Mybatis的foreach标签的使用以及参数的含义

Mybatis的foreach标签的使用以及参数的含义 语法格式&#xff1a; 属性说明&#xff1a; collection属性的注意点&#xff1a;

node js 递归生成vue文件目录

目录 什么是 fs 文件系统模块 fs.existsSync方法 方法说明&#xff1a; 语法&#xff1a; 向指定的文件中写入内容 writeFile fs.writeFile() 的语法格式 fs.writeFile() 的示例代码 判断文件是否写入成功 fs.mkdir 创建目录 目录已存在&#xff0c;重复创建 创建的目…

Python:Anaconda

简介 Anaconda是一个流行的Python发行版&#xff0c;专为科学计算和数据分析而设计。它包含了Python语言、Jupyter Notebook以及用于科学计算的众多包&#xff0c;如NumPy、Pandas、Matplotlib等。 Anaconda的特点是开箱即用&#xff0c;用户无需单独安装这些包&#xff0c;极…

Leetcode—459.重复的子字符串【简单】

2023每日刷题&#xff08;五十九&#xff09; Leetcode—459.重复的子字符串 算法思想 巧解的算法思想 实现代码 从第一个位置开始到s.size()之前&#xff0c;看s字符串是否是ss的子串 class Solution { public:bool repeatedSubstringPattern(string s) {return (s s).fin…

2023全球开发者生态调研:84%的开发者表示他们在工作中正积极使用生成式AI工具

今年JetBrains首次在一年一度的开发者生态调研中&#xff0c;增加了人工智能方向的问题。在全球26348名开发者参与的调研中&#xff0c;总体对人工智能的发展持乐观态度。特别是生成式AI在软件开发和编程环节中的应用&#xff0c;84%的开发者表示他们在工作中正在积极使用生成式…

占位图片(Placeholder Image)

一、引言 在网页设计和开发中&#xff0c;占位图片&#xff08;Placeholder Image&#xff09;是一种常见的技术手段&#xff0c;用于在用户上传图片之前或者图片加载失败时&#xff0c;展示一个临时替代的图片&#xff0c;以提高用户体验。本文将详细介绍占位图片的实现原理和…

中医电子处方管理系统软件,中医配方模板一键生成软件操作教程

一、前言&#xff1a; 在中医开电子处方时&#xff0c;如果能够使用配方模板功能&#xff0c;则可以节省很多时间。使用配方模板一键导入&#xff0c;几秒即可完成开单。 下面就以佳易王电子处方管理系统软件V17.1版本为例说明&#xff0c;其他版本可以参考&#xff0c;软件下…

获取 VirtualBox COM 对象失败,应用程序被终端 0x80000405错误解决以及Virtualbox下载

错误详情展示及解决_情况一 返回代码展示&#xff1a; 解决方式&#xff1a;打开在virtualbox的安装目录&#xff0c;找到VirtualBox.xml文件&#xff0c;将它删掉找到 错误详情展示及解决_情况二 返回代码展示&#xff1a; 情况说明&#xff1a; 原来是win10的电脑&#xf…

「Verilog学习笔记」加减计数器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1nsmodule count_module(input clk,input rst_n,input mode,output reg [3:0]number,output reg zero);reg [3:0] num ; always (posedge clk or negedge r…

计算两股不同流量的气体,通过换热器换热后,高温气体的出口温度

# -*- coding: utf-8 -*- """ Created on Thu Nov 30 11:23:12 2023 计算两股不同流量的气体&#xff0c;通过换热器换热后&#xff0c;高温气体的出口温度 (煤烟二级&#xff0c;计算煤烟二级热侧出口温度) ------------------------------------------------ …