Spring与IoC

Spring与IoC

一、IoC概述

  • 控制反转(IoC,Inversion of Control),是一个概念,是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,其实现方式多种多样。当前比较流行的实现方式有两种:依赖注入和依赖查找。依赖注入方式应用更为广泛。

  • 依赖查找:
    Dependency Lookup,DL,容器提供回调接口和上下文环境给组件,程序代码则需要提供具体的查找方式。比较典型的是依赖于 JNDI 服务接口(Java Naming and
    Directory Interface)的查找。

  • 依赖注入:
    Dependency Injection,DI,程序代码不做定位查询,这些工作由容器自行完成。依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。
    Spring 的依赖注入对调用者与被调用者几乎没有任何要求,完全支持 POJO 之间依赖关系的管理。依赖注入是目前最优秀的解耦方式。依赖注入让 Spring 的 Bean 之间以配置文件的方式
    组织在一起,而不是以硬编码的方式耦合在一起的。

二、Spring程序举例

  • 定义接口与实体类
public interface IStudentService{
    void some();
}
public class SatudentServiceImpl implements IStudentService{
    public void some(){
        System.out.println("执行some()方法");
    }
}
  • 创建Spring配置文件
    这里写图片描述
    bean标签 :用于定义一个实例对象。一个实例对应一个 bean 元素。
    id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。
    class:指定该 Bean 所属的类,注意这里只能是类,不能是接口。
  • 定义测试类
@Test
public void test03(){
    //获取容器
    ApplicationContext context=
    new ClassPathXmlApplicationContext("application.xml");
    //从容器获取对象
    IStudentService Service=(IStudentService)context.getBean("studentservice");
    service.some();
}

(1)ApplicationContext接口容器

ApplicationContext 用于加载 Spring 的配置文件,在程序中充当“容器”的角色。其实现类有两个。通过 Ctrl +T 查看:
这里写图片描述

A、配置文件在类路径下

  • 若Spring配置文件存放在项目的类路径下,则使用 ClassPathXmlApplicationContext 实现类进行加载。
ApplicationContext context=
    new ClassPathXmlApplicationContext("application.xml");

B、配置文件在本地目录中

  • 若 Spring 配置文件存放在本地磁盘目录中,则使用 FileSystemXmlApplicationContext 实现类进行加载。
ApplicationContext context=
    new FileSystemApplicationContext("d:/application.xml");

C、配置文件在项目根路径下

  • 若 Spring 配置文件存放在项目的根路径下,同样使用 FileSystemXmlApplicationContext实现类进行加载。存放在项目根路径下的情况,该配置文件与 src 目录同级,而非在 src 中。
ApplicationContext context=
    new FileSystemApplicationContext("application.xml");

(2)BeanFactory接口容器

  • BeanFactory 接口对象也可作为 Spring 容器出现。BeanFactory 接口是 ApplicationContext
    接口的父类
  • 若要创建 BeanFactory 容器,需要使用其实现XmlBeanFactory(Ctrl+T 查看继承关系)。该类可以加载 Spring 配置文件。
  • 而 Spring 配置文件以资源 Resouce 的形式出现在 XmlBeanFactory 类的构造器参数中。Resouce 是一个接口,其具有两个实现类:ClassPathResource:指定类路径下的资源文件、FileSystemResource:指定项目根路径或本地磁盘路径下的资源文件。
  • 在创建了 BeanFactory 容器后,便可使用其重载的 getBean()方法,从容器中获取指定的Bean 对象
    这里写图片描述

(3)两个接口容器的区别

  • 虽然这两个接口容器所要加载的 Spring 配置文件是同一个文件,但在代码中的这两个容器对象却不是同一个对象,即不是同一个容器:它们对于容器内对象的装配(创建)时机是不同的。
  • ApplicationContext 容器中对象的装配时机:
    ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。以后代码中若要使用到这些对象,只需从内存中直接获取即可。执行效率较高。但占用内存。
  • BeanFactory 容器中对象的装配时机:
    BeanFactory 容器,对容器中对象的装配与加载采用延迟加载策略,即在第一次调用getBean()时,才真正装配该对象。

三、Bear的装配

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

(1)默认装配方式

  • 代码通过 getBean()方式从容器获取指定的 Bean 实例,容器首先会调用 Bean 类的无参构造器,创建空值的实例对象。

(2)动态工厂 Bean

  • 有些时候,项目中需要通过工厂类来创建 Bean 实例,而不能像前面例子中似的,直接由 Spring 容器来装配 Bean 实例。使用工厂模式创建 Bean 实例,就会使工厂类与要创建的Bean 类耦合到一起。

(3)静态工厂 Bean

  • 使用工厂模式中的静态工厂来创建实例 Bean。此时需要注意,静态工厂无需工厂实例,所以不再需要定义静态工厂bean。而对于工厂所要创建的 Bean,其不是由自己的类创建的,所以无需指定自己的类。但其是由工厂类创建的,所以需要指定所用工厂类。故 class 属性指定的是工厂类而非自己的类。当然,还需要通过 factory-method 属性指定工厂方法。

(4)容器中Bear的作用域

  • 当通过 Spring 容器创建一个 Bean 实例时,不仅可以完成 Bean 的实例化,还可以通过scope 属性,为 Bean 指定特定的作用域。Spring 支持 5 种作用域。

    • singleton:单态模式。即在整个 Spring 容器中,使用 singleton 定义的 Bean 将是单例的,只有一个实例。默认为单态的。
    • prototype:原型模式。即每次使用 getBean 方法获取的同一个bean 的实例都是一个新的实例。
    • request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
    • session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。

    注意:
    (1)对于 scope 的值 request、session 与 global session,只有在 Web 应用中使用 Spring 时,该作用域才有效。
    (2)对于 scope 为 singleton 的单例模式,该 Bean 是在容器被创建时即被装配好了。
    (3)对于 scope 为 prototype 的原型模式,Bean 实例是在代码中使用该 Bean 实例时才进行装配的。

(5)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 属性值。

(6)定制Bean的生命始末

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

(7)Bean的生命周期

Step1:调用无参构造器,创建实例对象。
Step2:调用参数的 setter,为属性注入值。
Step3:若 Bean 实现了 BeanNameAware 接口,则会执行接口方法 setBeanName(String beanId),使 Bean 类可以获取其在容器中的 id 名称。
Step4:若 Bean 实现了 BeanFactoryAware 接口,则执行接口方法 setBeanFactory(BeanFactoryfactory),使 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 方法,则执行。

四、基于XML的DI

(1)注入分类

  • Bean 实例在调用无参构造器创建了空值对象后,就要对 Bean 对象的属性进行初始化。初始化是由容器自动完成的,称为注入。根据注入方式的不同,常用的有两类:设值注入、构造注入。还有另外一种,实现特定接口注入。由于这种方式采用侵入式编程,污染了代码,所以几乎不用。

1,设值注入

  • 设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在 Spring 的依赖注入中大量使用。
    这里写图片描述
  • 当指定 bean 的某属性值为另一 bean 的实例时,通过 ref 指定它们间的引用关系。ref的值必须为某 bean 的 id 值。
    这里写图片描述
  • 对于其它 Bean 对象的引用,除了标签的 ref 属性外,还可以使用ref标签。
    这里写图片描述

1,构造注入

  • 构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。即,使用构造器设置依赖关系。
    这里写图片描述

这里写图片描述
constructor-arg 标签中用于指定参数的属性有:
name:指定参数名称。
index:指明该参数对应着构造器的第几个参数,从 0 开始。不过,该属性不要也行,但要注意,若参数类型相同,或之间有包含关系,则需要保证赋值顺序要与构造器中的参数顺序一致。
另外,type 属性可用于指定其类型。基本类型直接写类型关键字即可,非基本类型需要写全限定性类名。

(2)集合属性注入
* 集合:

public class MyController{
    private String [] strs;
    private List<Student> students;
    private Set<String> myset;
    private Map<String,Integer> myMap;
    private Properties myPro;
}

1,为数组注入值
这里写图片描述
2,为 List 注入值
这里写图片描述
3,为 Set 注入值
这里写图片描述
4,为 Map 注入值
这里写图片描述
5,为 Properties 注入值
这里写图片描述

(3)对于域属性的自动注入

  • 对于域属性的注入,也可不在配置文件中显示的注入。可以通过为bean标签设置autowire 属性值,为域属性进行隐式自动注入。根据自动注入判断标准的不同,可以分为两种:
    byName:根据名称自动注入
    byType:根据类型自动注入

    1,byName 方式自动注入:当配置文件中被调用者 Bean 的 id 值与代码中调用者 Bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 Bean 注入给调用者 Bean。容器是通过调用者的 Bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。
    2,byType 方式自动注入:使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 Bean 类的某域属性类型同源。即要么相同,要么有 is-a 关系(子类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个了。

(4)为应用指定多个 Spring 配置文件

  • 将配置文件分解为地位平等的多个配置文件,并将所有配置文件的路径定义为一个String 数组,将其作为容器初始化参数出现。其将与可变参的容器构造器匹配。

1,平等关系的配置文件
* 将配置文件分解为地位平等的多个配置文件,并将所有配置文件的路径定义为一个String 数组,将其作为容器初始化参数出现。其将与可变参的容器构造器匹配。
这里写图片描述

2,包含关系的配置文件
* 各配置文件中有一个总文件,总配置文件将各其它子文件通过引入。在 Java代码中只需要使用总配置文件对容器进行初始化即可。
这里写图片描述

五、基于注解的DI
https://blog.csdn.net/king_cannon_fodder/article/details/80170665

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值