Spring IOC详解 快速入门

Spring 与 IoC

IoC (IOC,Inversion of Control)是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式有两种:依赖注入和依赖查找。依赖注入方式应用更为广泛。
依赖查找:Dependency Lookup,DL,容器提供回调接口和上下文环境给组件,程序代码则需要提供具体的查找方式。比较典型的是依赖于 JNDI 系统的查找。
依赖注入:Dependency Injection,DI,程序代码不做定位查询,这些工作由容器自行完成。
依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。
Spring 的依赖注入对调用者与被调用者几乎没有任何要求,完全支持 POJO 之间依赖关系的管理。
依赖注入是目前最优秀的解耦方式。依赖注入让 Spring 的 Bean 之间以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起的。

spring程序开发

在普通三层架构的基础上,将程序修改为 Spring 框架程序
举例:springDemo

导入 Jar 包

首先,导入 Spring 程序开发的四个基本 jar 包。
在这里插入图片描述
其次,导入日志相关的 Jar 包。
在 依 赖 库 spring-framework-3.0.2.RELEASE-dependencies.zip 解 压 目 录 下 :\org.apache.commons\com.springsource.org.apache.commons.logging\1.1.1 下 的com.springsource.org.apache.commons.logging-1.1.1.jar 文件。该文件只是日志记录的实现规范,并没有具体的实现。相当于 slf4j.jar 的作用。
这里日志的实现使用 log4j,故还需要 log4j.jar。在依赖库解压目录下:\org.apache.log4j\com.springsource.org.apache.log4j\1.2.15 中的 com.springsource.org.apache.log4j-1.2.15.jar最后,导入 JUnit 测试 Jar 包 junit-4.9.jar。
Spring 基本编程,共需 7 个 Jar 包即可。
在这里插入图片描述

定义接口与实体类

在这里插入图片描述
在这里插入图片描述

创建 Spring 配置文件

Spring 配置文件的文件名可以随意,但 Spring 建议的名称为 applicationContext.xml。文件约束在%SPRING_HOME%\docs\spring-framework-reference\html\xsd-configuration.html 文件中。
在这里插入图片描述
在这里插入图片描述
注意,Spring 配置文件中使用的约束文件为 xsd 文件。若 Eclipse 中没有自动提示功能,则需要将约束要查找的域名地址指向本地的 xsd 文件。相应的 xsd 文件在 Spring 框架解压目录下的 schema 目录的相应子目录中。
这里需要的是 spring-beans.xsd 约束文件,故需要在 beans 子目录中查找相应版本的约束文件。
在这里插入图片描述
在这里插入图片描述
< bean />:用于定义一个实例对象。一个实例对应一个 bean 元素。
id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。
class:指定该 Bean 所属的类,注意这里只能是类,不能是接口。

定义测试类

在这里插入图片描述
(1)ApplicationContext 接口容器
ApplicationContext 用于加载 Spring 的配置文件,在程序中充当“容器”的角色。其实现
类有两个。通过 Ctrl +T 查看:
在这里插入图片描述
A、配置文件在类路径下
若 Spring 配置文件存放在项目的类路径下,则使用ClassPathXmlApplicationContext 实现类进行加载。
在这里插入图片描述
B、配置文件在本地目录中
若 Spring 配置文件存放在本地磁盘目录中,则使用 FileSystemXmlApplicationContext 实现类进行加载。
在这里插入图片描述
C、配置文件在项目根路径下
若 Spring 配置文件存放在项目的根路径下,同样使用 FileSystemXmlApplicationContext实现类进行加载。下面是存放在项目根路径下的情况,该配置文件与 src 目录同级,而非在 src 中。
在这里插入图片描述
在这里插入图片描述(2)BeanFactory 接口容器
BeanFactory 接口对象也可作为 Spring 容器出现。BeanFactory 接口是 ApplicationContext接口的父类。
在这里插入图片描述
若要创建 BeanFactory 容器,需要使用其实现类 XmlBeanFactory(Ctrl+T 查看继承关系)。该类可以加载 Spring 配置文件。
在这里插入图片描述
而 Spring 配置文件以资源 Resouce 的形式出现在 XmlBeanFactory 类的构造器参数中。Resouce 是一个接口,其具有两个实现类:
ClassPathResource:指定类路径下的资源文件
FileSystemResource:指定项目根路径或本地磁盘路径下的资源文件。
在这里插入图片描述
在创建了 BeanFactory 容器后,便可使用其重载的 getBean()方法,从容器中获取指定的Bean 对象。
在这里插入图片描述
在这里插入图片描述
(3)两个接口容器的区别
虽然这两个接口容器所要加载的 Spring 配置文件是同一个文件,但在代码中的这两个容器对象却不是同一个对象,即不是同一个容器:它们对于容器内对象的装配(创建)时机是不同的。
装配时机测试时需要注意,首先要在容器中对象StudentServiceImpl 类的无参构造器中添加一个输出语句,以显示其是否执行。
在这里插入图片描述
A、ApplicationContext 容器中对象的装配时机
ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。
以后代码中若要使用到这些对象,只需从内存中直接获取即可。执行效率较高。但占用内存。
在这里插入图片描述
B、BeanFactory 容器中对象的装配时机
BeanFactory 容器,对容器中对象的装配与加载采用延迟加载策略,即在第一次调用getBean()时,才真正装配该对象。
在这里插入图片描述

Bean的装配

举例:beanAssemble 项目Bean 的装配,即 Bean 对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码的过程,称为 Bean 的装配。

默认装配方式

代码通过 getBean()方式从容器获取指定的 Bean 实例,容器首先会调用 Bean 类的无参构造器,创建空值的实例对象。
举例:ba01 包
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

动态工厂 Bean

有些时候,项目中需要通过工厂类来创建 Bean 实例,而不能像前面例子中似的,直接由 Spring 容器来装配 Bean 实例。使用工厂模式创建 Bean 实例,就会使工厂类与要创建的Bean 类耦合到一起。
(1)将动态工厂 Bean 作为普通 Bean 使用
将动态工厂 Bean 作为普通 Bean 来使用是指,在配置文件中注册过动态工厂 Bean 后,测试类直接通过 getBean()获取到工厂对象,再由工厂对象调用其相应方法创建相应的目标对象。配置文件中无需注册目标对象的 Bean。因为目标对象的创建不由 Spring 容器来管理。
举例:ba02 包
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
但,这样做的缺点是,不仅工厂类与目标类耦合到了一起,测试类与工厂类也耦合到了一起。
(2)使用 Spring 的动态工厂 Bean
Spring 对于使用动态工厂来创建的 Bean,有专门的属性定义。factory-bean 指定相应的工厂 Bean,由 factory-method 指定创建所用方法。此时配置文件中至少会有两个 Bean 的定义:工厂类的 Bean,与工厂类所要创建的目标类 Bean。而测试类中不再需要获取工厂 Bean对象了,可以直接获取目标 Bean 对象。实现测试类与工厂类间的解耦。
在这里插入图片描述
在这里插入图片描述

静态工厂 Bean

使用工厂模式中的静态工厂来创建实例 Bean。
此时需要注意,静态工厂无需工厂实例,所以不再需要定义静态工厂。
而对于工厂所要创建的 Bean,其不是由自己的类创建的,所以无需指定自己的类。但其是由工厂类创建的,所以需要指定所用工厂类。故 class 属性指定的是工厂类而非自己的类。当然,还需要通过 factory-method 属性指定工厂方法。
举例:ba03 包
在这里插入图片描述
在这里插入图片描述
容器中 Bean 的作用域
当通过 Spring 容器创建一个 Bean 实例时,不仅可以完成 Bean 的实例化,还可以通过scope 属性,为 Bean 指定特定的作用域。Spring 支持 5 种作用域。
(1)singleton:单态模式。即在整个 Spring 容器中,使用 singleton 定义的 Bean 将是单例的,只有一个实例。默认为单态的。
(2)prototype:原型模式。即每次使用 getBean 方法获取的同一个的实例都是一个新的实例。
(3)request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
(4)session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。
(5)global session:每个全局的 HTTP session 对应一个 Bean 实例。典型情况下,仅在使用portlet 集群时有效,多个 Web 应用共享一个 session。一般应用中,global-session 与 session是等同的。
注意:
(1)对于 scope 的值 request、session 与 global session,只有在 Web 应用中使用 Spring 时,该作用域才有效。
(2)对于 scope 为 singleton 的单例模式,该 Bean 是在容器被创建时即被装配好了。 (3)对于 scope 为 prototype 的原型模式,Bean 实例是在代码中使用该 Bean 实例时才进行装配的。
举例:ba04 包
在这里插入图片描述
在这里插入图片描述

Bean 后处理器

Bean 后处理器是一种特殊的 Bean,容器中所有的 Bean 在初始化时,均会自动执行该类的两个方法。由于该 Bean 是由其它 Bean 自动调用执行,不是程序员手工调用,故此 Bean无须 id 属性。
需要做的是,在 Bean 后处理器类方法中,只要对 Bean 类与 Bean 类中的方法进行判断,就可实现对指定的 Bean 的指定方法进行功能扩展与增强。方法返回的 Bean 对象,即是增过的对象。
代码中需要自定义 Bean 后处理器类。该类就是实现了接口 BeanPostProcessor 的类。该接口中包含两个方法,分别在目标 Bean 初始化完毕之前与之后执行。它们的返回值为:功能被扩展或增强后的 Bean 对象。
Bean 初始化完毕有一个标志:一个方法将被执行。即当该方法被执行时,表示该 Bean被初始化完毕。所以 Bean 后处理器中两个方法的执行,是在这个方法之前之后执行。这个方法在后面将会讲到。
public Object postProcessBeforeInitialization(Object bean, String beanId) throws BeansException
该方法会在目标 Bean 初始化完毕之前由容器自动调用。
public Object postProcessAfterInitialization(Object bean, String beanId) throws BeansException
该方法会在目标 Bean 初始化完毕之后由容器自动调用。
它们的参数是:第一个参数是系统即将初始化的 Bean 实例,第二个参数是该 Bean 实例的 id 属性值。若 Bean 没有 id 就是 name 属性值。
举例: ba05 包
程序中有一个业务接口 IService,其有两个业务方法 some()与 other()。有两个 Bean:StudentServiceImpl 与 TeacherServiceImpl,均实现了 IService 接口。
要求:对 StudentServiceImpl 的 some()方法进行增强,输出其开始执行时间与执行结束时间
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

定制 Bean 的生命始末

可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。
举例:ba06 包。
首先,这些方法需要在 Bean 类中事先定义好:是方法名随意的 public void 方法。
在这里插入图片描述
其次,在配置文件的标签中增加如下属性:
init-method:指定初始化方法的方法名destroy-method:指定销毁方法的方法名
在这里插入图片描述
在这里插入图片描述
注意,若要看到 Bean 的 destroy-method 的执行结果,需要满足两个条件:
(1)Bean 为 singleton,即单例
(2)要确保容器关闭。接口 ApplicationContext 没有 close()方法,但其实现类有。所以,可以将 ApplicationContext 强转为其实现类对象,或直接创建的就是实现类对象。

Bean 的生命周期

Bean 实例从创建到最后销毁,需要经过很多过程,执行很多生命周期方法。
Step1:调用无参构造器,创建实例对象。
Step2:调用参数的 setter,为属性注入值。
Step3:若 Bean 实现了 BeanNameAware 接口,则会执行接口方法 setBeanName(String beanId), 使 Bean 类可以获取其在容器中的 id 名称。
Step4:若 Bean 实现了 BeanFactoryAware 接口,则执行接口方法 setBeanFactory(BeanFactory factory),使 Bean 类可以获取到 BeanFactory 对象。
Step5 : 若 定 义 并 注 册 了 Bean 后 处 理 器 BeanPostProcessor , 则 执 行 接 口 方 法postProcessBeforeInitialization()。
Step6:若 Bean 实现了 InitializingBean 接口,则执行接口方法 afterPropertiesSet ()。该方法在 Bean 的所有属性的 set 方法执行完毕后执行,是 Bean 初始化结束的标志,即 Bean 实例化结束。
Step7:若设置了 init-method 方法,则执行。
Step8 : 若 定 义 并 注 册 了 Bean 后 处 理 器 BeanPostProcessor , 则 执 行 接 口 方 法postProcessAfterInitialization()。
Step9:执行业务方法。
Step10:若 Bean 实现了 DisposableBean 接口,则执行接口方法 destroy()。
Step11:若设置了 destroy-method 方法,则执行。
举例:ba07 包

< bean/>标签的 id 属性与 name 属性

一般情况下,命名使用 id 属性,而不使用 name 属性。在没有 id 属性的情况下,name 属性与 id 属性作用是相同的。但,当中含有一些特殊字符时,就需要使用 name属性了。
id 的命名需要满足 XML 对 ID 属性命名规范:必须以字母开头,可以包含字母、数字、下划线、连字符、句话、冒号。
name 属性值则可以包含各种字符。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值