当前位置: 首页 > news >正文

SpringIoc 实践和应用--XML配置

1SpringIoc/DI实现步骤

1.1配置元数据

配置元数据,是编写交给SpringIoc容器管理组件的信息,配置方式主要有三种。

基于XML的元数据配置基本结构:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 此处要添加一些约束,配置文件的标签并不是随意命名 -->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="..." [1] class="..." [2]>  </bean><bean id="..." class="..."></bean></beans>

Ioc容器管理一个或多个组件。这些组件是使用提供的元数据构成的

id:标识单个Bean定义的字符串

class:定义Bean类型并使用完全限定的类名。

1.2实例化容器

提供ApplicationContext构造函数的位置路径是资源字符串地址,允许容器从各种外部资源路径加载配置元数据。我们可以选择一个合适的实现类来进行实例化工作。

例如:

//实例化ioc容器,读取外部配置文件,最终会在容器内进行ioc和di动作
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

1.3获取Bean组件

ApplicationContext 是一个高级工厂的接口,能够维护不同 bean 及其依赖项的注册表。通过使用方法 T getBean(String name, Class<T> requiredType) ,您可以检索 bean 的实例。

//创建ioc容器对象,指定配置文件,ioc也开始实例组件对象
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
//获取ioc容器的组件对象
PetStoreService service = context.getBean("petStore", PetStoreService.class);
//使用组件对象
List<String> userList = service.getUsernameList();

2.基于XML的配置方式管理组件

2.1思路

将自定义的组件类配置到Spring Ioc容器当中去,然后IOC容器对象通过对应的接口类读取配置文件,然后创建组件对象。

2.2实验

导入依赖:

<dependencies><!--spring context依赖--><!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.6</version></dependency><!--junit5测试--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.3.1</version></dependency>
</dependencies>

2.2.1基于无参构造器

准备组件类:

public class Main{public void doWork() {System.out.println("Hello world!");}
}

编写配置文件:resources/spring-bean-01.xml

<!-- 实验一 [重要]创建bean -->
<bean id="main" class="com.ioc.Main"/>
  • bean标签:通过bean标签告诉IOC容器需要创建组件的信息。
  • id属性:bean的唯一标识符,方便后面获取bean。
  • class属性:可以理解为src目录开始一直到哪个包下的哪个类。
  • 要求当前类必须包含无参构造器。

2.2.2基于静态工厂方法实例化

准备组件:

public class ClientService {private static ClientService clientService = new ClientService();private ClientService() {}public static ClientService createInstance() {return clientService;}
}

编写配置文件:

<bean id="clientService"class="examples.ClientService"factory-method="createInstance"/>
  • class属性:指定工厂类的全限定符!
  • factory-method: 指定静态工厂方法,注意,该方法必须是static方法。

2.2.3基于实例工厂方法实例化

准备组件类

public class DefaultServiceLocator {private static ClientServiceImplclientService = new ClientServiceImpl();public ClientService createClientServiceInstance() {return clientService;}
}

配置文件编写这个主要是用来配非静态的方法的

<!-- 将工厂类进行ioc配置 -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
</bean><!-- 根据工厂对象的实例工厂方法进行实例化组件对象 -->
<bean id="clientService"factory-bean="serviceLocator"factory-method="createClientServiceInstance"/>
  • factory-bean属性:指定当前容器中工厂Bean 的名称。
  • factory-method: 指定实例工厂方法名。注意,实例方法必须是非static的

2.3组件依赖注入配置(DI)

2.3.1DI注入场景和作用

目标:通过配置文件,实现Ioc容器中Bean之间的引用(依赖注入DI配置)

主要涉及诸如场景:基于构造函数的依赖注入和基于Setter的依赖注入

2.3.2基于构造函数的依赖注入(单个构造函数)

准备组件:

public class UserDao {
}public class UserService {private UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}
}

配置文件编写

<beans>
声明引用类<bean id = "userService" class = "x.y.UserService">
构造函数引用<constructor-arg ref = "userDao"/></bean>
被引用类的bean声明<bean id="userDao" class="x.y.UserDao"/>
</beans>

2.3.3基于构造函数的依赖注入(多个参数的构造函数的解析)

介绍:基于构造函数的 DI 是通过容器调用具有多个参数的构造函数来完成的,每个参数表示一个依赖项。

准备组件

public class UserDao {
}public class UserService {private UserDao userDao;private int age;private String name;public UserService(int age , String name ,UserDao userDao) {this.userDao = userDao;this.age = age;this.name = name;}
}

编写配置文件:

<!-- 场景1: 多参数,可以按照相应构造函数的顺序注入数据 -->
<beans><bean id="userService" class="x.y.UserService"><!-- value直接注入基本类型值 --><constructor-arg  value="18"/><constructor-arg  value="张三"/><constructor-arg  ref="userDao"/></bean><!-- 被引用类bean声明 --><bean id="userDao" class="x.y.UserDao"/>
</beans>
<!-- 场景2: 多参数,可以按照相应构造函数的名称注入数据 -->
<beans><bean id="userService" class="x.y.UserService"><!-- value直接注入基本类型值 --><constructor-arg name="name" value="张三"/><constructor-arg name="userDao" ref="userDao"/><constructor-arg name="age"  value="18"/></bean><!-- 被引用类bean声明 --><bean id="userDao" class="x.y.UserDao"/>
</beans>
<!-- 场景2: 多参数,可以按照相应构造函数的角标注入数据index从0开始 构造函数(0,1,2....)-->
<beans><bean id="userService" class="x.y.UserService"><!-- value直接注入基本类型值 --><constructor-arg index="1" value="张三"/><constructor-arg index="2" ref="userDao"/><constructor-arg index="0"  value="18"/></bean><!-- 被引用类bean声明 --><bean id="userDao" class="x.y.UserDao"/>
</beans>
  • constructor-arg标签:指定构造器对应的值
  • constructor-arg标签:name属性指定参数名,index属性指定参数索引,value属性指定普通属性值

2.3.4基于Setter方法依赖注入

介绍:开发中,除了构造函数注入(DI)更多的使用的Setter方法进行注入!

准备组件:

public Class MovieFinder{}public class SimpleMovieLister {private MovieFinder movieFinder;private String movieName;public void setMovieFinder(MovieFinder movieFinder) {this.movieFinder = movieFinder;}public void setMovieName(String movieName){this.movieName = movieName;}
}

编写配置文件:

<bean id="simpleMovieLister" class="examples.SimpleMovieLister"><!-- setter方法,注入movieFinder对象的标识idname = 属性名  ref = 引用bean的id值--><property name="movieFinder" ref="movieFinder" /><!-- setter方法,注入基本数据类型movieNamename = 属性名 value= 基本类型值--><property name="movieName" value="消失的她"/>
</bean><bean id="movieFinder" class="examples.MovieFinder"/>

property标签:可以给setter方法对应的属性赋值

property标签:name属性代表set方法的表示,ref代表引用bean的标识id,value属性代表的基本属性。

3.Ioc容器创建和使用

上面只是讲述了如何在XML格式配置文件编写Ioc和DI配置,接下来我们来说如何使用

//实现一个接口
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml","daos.xml");

bean对象的读取

//方式1: 根据id获取
//没有指定类型,返回为Object,需要类型转化!
HappyComponent happyComponent = (HappyComponent) iocContainer.getBean("bean的id标识");//使用组件对象        
happyComponent.doWork();//方式2: 根据类型获取
//根据类型获取,但是要求,同类型(当前类,或者之类,或者接口的实现类)只能有一个对象交给IoC容器管理
//配置两个或者以上出现: org.springframework.beans.factory.NoUniqueBeanDefinitionException 问题
HappyComponent happyComponent = iocContainer.getBean(HappyComponent.class);
happyComponent.doWork();//方式3: 根据id和类型获取
HappyComponent happyComponent = iocContainer.getBean("bean的id标识", HappyComponent.class);
happyComponent.doWork();根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类型』的返回结果,
只要返回的是true就可以认定为和类型匹配,能够获取到。

4.组件作用域和周期方法配置

4.1周期方法概念

我们可以在组件类中定义方法,然后当IoC容器实例化和销毁组件对象的时候进行调用!这两个方法我们成为生命周期方法!

类似于Servlet的init/destroy方法,我们可以在周期方法完成初始化和释放资源等工作。

周期方法声明:

public class BeanOne {//周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表public void init() {// 初始化逻辑}
}public class BeanTwo {public void cleanup() {// 释放资源逻辑}
}

周期方法配置

<beans><bean id="beanOne" class="examples.BeanOne" init-method="init" /><bean id="beanTwo" class="examples.BeanTwo" destroy-method="cleanup" />
</beans>

4.2作用域可选值

Scope:可取值singleton或prototype

singleton在Ioc容器中,这个bean的对象始终为单实例。

prototype在Ioc容器中有多个实例。

<!--bean的作用域 准备两个引用关系的组件类即可!!
-->
<!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建对象 -->
<!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 -->
<bean id="happyMachine8" scope="prototype" class="com.atguigu.ioc.HappyMachine"><property name="machineName" value="happyMachine"/>
</bean><bean id="happyComponent8" scope="singleton" class="com.atguigu.ioc.HappyComponent"><property name="componentName" value="happyComponent"/>
</bean>

5.FactoryBean的使用特性

5.1FactoryBean简介

`FactoryBean` 接口是Spring IoC容器实例化逻辑的可插拔性点。

准备实现类:

// 实现FactoryBean接口时需要指定泛型
// 泛型类型就是当前工厂要生产的对象的类型
public class HappyFactoryBean implements FactoryBean<HappyMachine> {private String machineName;public String getMachineName() {return machineName;}public void setMachineName(String machineName) {this.machineName = machineName;}@Overridepublic HappyMachine getObject() throws Exception {// 方法内部模拟创建、设置一个对象的复杂过程HappyMachine happyMachine = new HappyMachine();happyMachine.setMachineName(this.machineName);return happyMachine;}@Overridepublic Class<?> getObjectType() {// 返回要生产的对象的类型return HappyMachine.class;}
}

配置实现

<!-- FactoryBean机制 -->
<!-- 这个bean标签中class属性指定的是HappyFactoryBean,但是将来从这里获取的bean是HappyMachine对象 -->
<bean id="happyMachine7" class="com.atguigu.ioc.HappyFactoryBean"><!-- property标签仍然可以用来通过setXxx()方法给属性赋值 --><property name="machineName" value="iceCreamMachine"/>
</bean>

测试读取

@Test
public void testExperiment07()  {ApplicationContext iocContainer = new ClassPathXmlApplicationContext("spring-bean-07.xml");//注意: 直接根据声明FactoryBean的id,获取的是getObject方法返回的对象HappyMachine happyMachine = iocContainer.getBean("happyMachine7",HappyMachine.class);System.out.println("happyMachine = " + happyMachine);//如果想要获取FactoryBean对象, 直接在id前添加&符号即可!  &happyMachine7 这是一种固定的约束Object bean = iocContainer.getBean("&happyMachine7");System.out.println("bean = " + bean);
}

输出结果分析:

  1. 第一行输出的是通过happyMachine7获取到的HappyMachine实例对象。这是因为当我们通过 FactoryBean 的 id 获取 bean 时,Spring 会自动调用 FactoryBean 的getObject()方法,返回泛型指定的HappyMachine类型对象,并且该对象的machineName属性已经被设置为 "iceCreamMachine"。

  2. 第二行输出的是通过&happyMachine7获取到的HappyFactoryBean实例本身。在 Spring 中,这是一个特殊约定:在 bean 的 id 前加上&符号,就可以获取到 FactoryBean 对象本身,而不是它所生产的对象。

**FactoryBean **是 Spring 中一种特殊的 bean,可以在 getObject() 工厂方法自定义的逻辑创建Bean!是一种能够生产其他 Bean 的 Bean。FactoryBean 在容器启动时被创建,而在实际使用时则是通过调用 getObject() 方法来得到其所生产的 Bean。因此,FactoryBean 可以自定义任何所需的初始化逻辑,生产出一些定制化的 bean。

**BeanFactory** 是 Spring 框架的基础,其作为一个顶级接口定义了容器的基本行为,例如管理 bean 的生命周期、配置文件的加载和解析、bean 的装配和依赖注入等。BeanFactory 接口提供了访问 bean 的方式,例如 getBean() 方法获取指定的 bean 实例。它可以从不同的来源(例如 Mysql 数据库、XML 文件、Java 配置类等)获取 bean 定义,并将其转换为 bean 实例。同时,BeanFactory 还包含很多子类(例如,ApplicationContext 接口)提供了额外的强大功能。

概括:FactoryBean是用来创建bean的接口的,BeanFactory是用来管理bean的框架基础的接口,提供了基本的内容功能和bean生命周期管理。

http://www.lryc.cn/news/616275.html

相关文章:

  • PHP版本控制系统:高效文档管理
  • MVC结构变种——第三章核心视图及控制器的整体逻辑
  • 计算机网络---IP(互联网协议)
  • 学习分库分表的前置知识:高可用系统架构理论与实践
  • Android视图回调机制:从post到ViewTreeObserver,从源码分析到最佳实践
  • java组件漏洞
  • 【在线五子棋对战】十二、http请求处理
  • 从 GPT‑2 到 gpt‑oss:解析架构的迭代
  • C++移动语义、完美转发及编译器优化零拷贝
  • win11(RTX5060)下进行nanodetplus训练
  • 2025年全国青少年信息素养大赛Scratch编程践挑战赛-小低组-初赛-模拟题
  • 动态工作流:目标结构源自表
  • 红楼梦文本数据分析
  • SpringBoot实现文件上传
  • CART算法:Gini指数
  • sqli-labs-master/Less-62~Less-65
  • 人工智能正在学习自我提升的方式
  • 《算法导论》第 17 章 - 摊还分析
  • 谷歌DeepMind发布Genie 3:通用型世界模型,可生成前所未有多样化的交互式虚拟环境
  • UE什么贴图要关闭SRGB
  • Virtio 驱动初始化数据收发流程详解
  • 太极行业观察:从传统技艺到数字化转型的演变|创客匠人
  • 【R studio数据分析】准备工作——下载安装
  • 【布局适配问题】响应式布局、移动端适配、大屏布局要点
  • 通过sealos工具在ubuntu 24.02上安装k8s集群
  • Loki+Alloy+Grafana构建轻量级的日志分析系统
  • FFmpeg实现音视频转码
  • Spring AOP 底层实现(面试重点难点)
  • AQS(AbstractQueuedSynchronizer)底层源码实现与设计思想
  • 前端路由:Hash 模式与 History 模式深度解析