您的位置 首页 java

Java Web轻松学23 – Spring IoC基于XML生产和装配Bean

本系列文章旨在记录和总结自己在 java  Web开发之路上的知识点、经验、问题和思考,原来已经分享在我的CSDN博客,现在分享在头条,希望能帮助更多码农和想成为码农的人。版权声明:本文为CSDN博主「普通的码农」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。原文链接:
 

目录

  1. 介绍
  2. 再谈 Spring 框架及其模块
  3. Spring的工作模式
  4. 工程结构
  5. 准备食材 – 开发业务组件
  6. 菜品制作清单 – 配置 元数据
  7. 聘请厨师兼菜品管理员 – Spring IoC容器
  8. IoC的含义和好处
  9. 总结

介绍

本篇文章介绍Spring IoC( Inversion of Control,控制反转 )是如何使用 XML 来装配 Bean 的。这里,Bean其实就是对象,还有很多其他说法,比如Java Bean、POJO(Plain Old Java Object,普通Java对象)等,都是差不多的意思,不必深究。

不过,以后文章中的Bean就专门指Spring IoC容器管理的对象。

准备工作:

  • 在Eclipse中新建Java工程:spring-ioc-test,可以参考 。
  • 在该工程中添加好Spring IoC模块的那几个JAR包,可以参考 。

再谈Spring框架及其模块

我们以后提到Spring框架,就是指官网中的Spring Framework这个项目,而不是指Spring Boot、Spring Data等其他项目,也不是指Spring Framework这个项目包含的某个模块比如Spring MVC等。

介绍了Spring框架的模块划分,它来源于《Spring实战第4版》:

而Spring官方文档()则将Spring框架分为以下几个部分来介绍:

也介绍过Spring的基础、核心模块就是生产、组装/装配对象,用专业一点的术语就是Spring框架提供了一个IoC(Inversion of Control,控制反转)容器,具体用的技术就是DI(Dependency Injection,依赖注入)。

所以综合以上两种分类,我们以后就使用 IoC 表示Spring框架的核心容器这一个模块,主要包括spring-beans-5.1.7.RELEASE.jar(后续简写为beans,下同)、context、context-indexer、context-support等JAR包。core这个JAR包包括了很多基础的工具,expression这个JAR包主要实现了Spring表达式语言,也一并归到IoC模块吧。

而将官方文档中Core模块中的 AOP (Aspect Oriented Programming,面向切面编程)独立出来。

Spring的工作模式

再次描述一下Spring的工作模式:

我们就根据这个工作模式来构建我们的应用系统。

整个系统就好像是厨师根据菜品制作清单,使用各种食材制作出一个个菜肴。

  • 厨师就是Spring IoC容器,生产并管理Bean;
  • 菜品制作清单就是配置元数据,描述了Bean是如何生产(依赖于代码级构件)和装配(依赖于其他Bean)的;
  • 食材就是业务组件,Bean的代码级构件;
  • 每个菜肴就是一个Bean。

感觉这个比喻也不怎么恰当,不过还是有一定类似之处的。

工程结构

先给出整个工程的结构:

这里就不再赘述如何 了,前面的文章已经介绍过了,新建XML文件也是类似。也不再赘述 了(图中的spring节点)。

配置元数据XML文件需要放在src节点下,这样后面使用 classpath XmlApplicationContext就可直接传入XML文件名称即可,因为src属于classpath下的一个路径,ClassPathXmlApplicationContext从类名上看就是从classpath中去寻找XML文件。

当然,还有FileSystemXmlApplicationContext之类的可以从其他地方去寻找XML文件。Spring框架提供了足够多的IoC容器给我们选择。

准备食材 – 开发业务组件

首先,在工程中开发你所需要的业务组件,我的业务组件包括:

  • 服务层的 service A、ServiceB
  • 数据访问层的RepositoryA、RepositoryB

所谓服务层,就是专门提供某种业务服务的。

一个业务服务可能要涉及到多种业务数据(业务实体)的读写操作,各种业务数据可能来自不同的数据源,比如有的来自文件系统,有的来自关系数据库,有的来自缓存,有的来自 NoSql 等等。所以,为了屏蔽这些差异,就有了数据访问层。

实际上,分层就是单一职责原则的体现,服务层就是用来计算数据的,数据访问层就是用来操作(读/写)数据的。

它们的依赖关系如下:

其实,这就是 架构设计 ,本质上就是划分职责,确定它们的依赖关系。当然,实际中的应用系统比这个复杂得多,这里只是用于演示基本原理和流程。

下面是各组件的代码。

ServiceA.java

package test.service;
import test.repository.RepositoryA;
public class ServiceA {
private ServiceB serviceB;
private RepositoryA repositoryA;

public ServiceA (ServiceB serviceB, RepositoryA repositoryA) {
this.serviceB = serviceB;
this.repositoryA = repositoryA;
}

public void doWork() {
System.out.println("ServiceA doWork start");
serviceB.doWork();
repositoryA.save();
System.out.println("ServiceA doWork end");
}
}
 

ServiceB.java

package test.service;
import test.repository.RepositoryB;
public class ServiceB {
private RepositoryB repositoryB;
public RepositoryB getRepositoryB() {
return repositoryB;
}
public void setRepositoryB(RepositoryB repositoryB) {
this.repositoryB = repositoryB;
}

public void doWork() {
System.out.println("ServiceB doWork start");
repositoryB.update();
System.out.println("ServiceB doWork end");
}
}
 

RepositoryA.java

package test.repository;
public class RepositoryA {
public void save() {
System.out.println("RepositoryA save ...");
}
}
 

RepositoryB.java

package test.repository;
public class RepositoryB {
public void update() {
System.out.println("RepositoryB update ...");
}
}
 

菜品制作清单 – 配置元数据

接下来,就需要编写我们的菜品制作清单,就是Spring IoC容器需要的配置元数据(Configuration Metadata,这是官方文档的说法)。

配置元数据的提供有三种方式:

  • 基于XML文档的最原始的方式;
  • 基于Java注解的自动扫描和装配的方式:Spring 2.5引入;
  • 基于Java配置的方式:Spring 3.0引入。

这篇文章我们先使用基于XML文档的方式。

spring-ioc-test.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""
xmlns:xsi=""
xsi:schemaLocation=" 
">

<bean id="svcA" class="test.service.ServiceA">
<constructor-arg name="serviceB" ref="svcB" />
<constructor-arg name="repositoryA" ref="repoA" />
</bean>

<bean id="svcB" class="test.service.ServiceB">
<property name="repositoyB" ref="repoB" />
</bean>

<bean id="repoA" class="test.repository.RepositoryA" />
<bean id="repoB" class="test.repository.RepositoryB" />
</beans>
 

关于XML的知识,我们暂且不细说,它类似于前面说的HTML,也是一种标记语言,也是使用尖括号,实际上它们很相似,渊源也颇深。

这里只关注以下几个重点标记。

  • beans标记 :它是整个配置的根标记。
  • bean标记 :定义了一个Bean,Spring IoC就是根据这个标记的内容来 生产和装配 Bean的。它有两个属性, id 表示该Bean在某个Spring IoC容器(一个应用中可以有多个Spring IoC容器)中的唯一标识; class 就是你的业务组件了,必须是全限定名称。
  • constructor-arg标记 :用于使用 构造器 生成Bean的时候,传递所依赖的 构造器参数 ,属性 name 表示参数名,跟代码中的构造器参数一致;属性 ref 表示该参数的值是一个引用,指向其他的Bean,填写其他Bean的id即可。这就是 构造器注入
  • property标记 :用于Bean已经生成,使用 setter方法注入 所依赖的Bean,这里的属性 name 指的是该Bean的某个属性的名字,跟代码中的类的属性名一致;属性 ref 的含义跟上面的一样。

上面的代码还可以看到,不依赖于任何其他Bean的Bean(比如上面的repoA和repoB)就不需要constructor-arg标记和/或property标记了。

这些标记其实也不难记,因为标记名称很容易就望文生义,顾名思义。

聘请厨师兼菜品管理员 – Spring IoC容器

食材和菜品制作清单已经准备好,最后就只需要厨师来烹制了,那我们应该怎么样聘请厨师呢?

SpringMain.java:

package test;
import org.springframework.context. ApplicationContext ;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.service.ServiceA;
public class SpringMain {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc-test.xml");
ServiceA svcA = context.getBean("svcA", ServiceA.class);
svcA.doWork();
}
}
 
  • ApplicationContext :这个接口即代表/描述了 Spring IoC容器 ,即它就是负责生产/实例化、配置、装配、管理那些Bean, 所以以后提到Spring IoC容器,其实就是一个ApplicationContext实例,聘请厨师不过就是生成一个ApplicationContext实例而已
  • ClassPathXmlApplicationContext :这是一个 具体的 Spring IoC容器,它在classpath中寻找指定的XML格式的配置元数据,然后根据清单生产并装配Bean。
  • getBean方法 :从容器中获取一个Bean,根据该Bean的id即可。
  • 剩下的就是 使用 从容器中获取到的Bean了。

当然,只有在程序运行时,才会真正实例化Spring IoC容器,然后它才根据配置元数据,生产和装配Bean。

IoC的含义和好处

其实,我们也可以像下面那样在代码中进行Bean的生产和装配:

Main.java:

package test;
import test.repository.RepositoryA;
import test.repository.RepositoryB;
import test.service.ServiceA;
import test.service.ServiceB;
public class Main {
public static void main(String[] args) {

RepositoryA repoA = new RepositoryA();
RepositoryB repoB = new RepositoryB();

ServiceB svcB = new ServiceB();
svcB.setRepositoyB(repoB);

ServiceA svcA = new ServiceA(svcB, repoA);

svcA.doWork();
}
}
 

这就是IoC(Inversion of Control,控制反转)的含义了,原来需要我们的代码甚至是Bean本身内部来 控制 它所依赖的Bean的生产,而现在将这种 控制权 交给了Spring IoC容器了。

那这样做有什么好处呢?最显然的好处是,代码中的new语句少了,这不就 消除重复 了吗。问题是这种重复不又跑到配置文件里去了吗,而且看起来配置文件要敲击的文字反而更多,这是基于XML的配置元数据的弊端,据说以前的Spring应用开发工程师疲于应付配置文件的这种繁冗。

这样带来的好处是依赖关系的 集中配置 ,这又是另外一大原则“ 物以类聚 ”的体现,而不是将依赖关系散布在代码的各个角落,这样很不清晰和不利于管理。

其次,基于XML的配置元数据很灵活, 依赖关系发生改变后不需要重新编译代码

其实,IoC的好处需要实践去体会,我理解的也不是很深刻。

总结

  • 所谓 架构设计 ,本质上就是划分职责,确定它们的依赖关系。
  • IoC 就是指Bean的生产和装配交给专门的组件来控制,而无需Bean本身来控制。
  • DI(依赖注入) 实际上就是由容器来将依赖关系注入到某个Bean。
  • IoC其中一个好处是 解耦
  • Spring IoC容器由 ApplicationContext 接口描述(当然,最底层是 BeanFactory 这个接口),具体的有很多种容器可以选择,比如ClassPathXmlApplicationContext等。
  • 基于XML的配置元数据主要是用于 生产 Bean的 <beans />和<bean />标记 ,用于 依赖注入 <constructor-arg />和<property />标记 ,前者用于 构造器注入 ,后者用于 setter方法注入

文章来源:智云一二三科技

文章标题:Java Web轻松学23 – Spring IoC基于XML生产和装配Bean

文章地址:https://www.zhihuclub.com/184797.shtml

关于作者: 智云科技

热门文章

网站地图