天天看点

Spring之IOC控制反转的理解

Spring IOC简介

beans和context包是IOC容器的基础,BeanFactory 提供的高级配置机制,使得管理各种对象成为可能。 ApplicationContext 是BeanFactory的扩展,功能得到了进一步增强,比如更易 与Spring AOP集成、资源处理(国际化处理)、事件传递及各种不同应用层的context实现 (如针对web应用的WebApplicationContext)。总之,在实际应用更多会选择ApplicationContext,原因是ApplicationContext即继承了BeanFactory的功能,同时又增加的更多支持企业核心内容的支持。

Spring IOC关键概念理解

IOC(Inversion of Control):控制反转,即指获取对象的方式被反转了,我们只需要在applicationContext.xml(Spring的配置文件)文件配置元数据(即指xml)中的bean指定相应class(类)的全路径,Spring中的容器(BeanFactory)会负责类对象的创建、配置和管理这些对象及它们之间的依赖关系,而且这些对象和我们通过new Object()的对象没有区别,这样最终会达到解耦的目的(即减少代码之间的依赖);

Bean:在Spring中,那些组成你应用程序的主体(backbone)及由Spring IoC容器所管理的对象,被称之为bean。 简单地讲,bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。 而bean定义以及bean相互间的依赖关系将通过配置元数据来描述。

容器:即指Spring IOC容器,BeanFactory是容器的实际代表者,他负责bean对象的创建,配置和容纳创建的bean描述并且管理bean;Spring为我们提供了许多易用的BeanFactory实现, XmlBeanFactory就是最常用的一个。该实现将以XML方式描述组成应用的对象以及对象间的依赖关系。XmlBeanFactory类将获取此XML配置元数据,并用它来构建一个完全可配置的系统或应用。

Spring之IOC控制反转的理解

Spring IOC 容器

元数据:我们通常配置的Spring配置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/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>

  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>

  <!-- more bean definitions go here -->

</beans>      

注入依赖:

依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其它对象)只会通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。因此,容器的工作就是创建bean时注入那些依赖关系。相对于由bean自己来控制其实例化、直接在构造器中指定依赖关系或者类似服务定位器(Service Locator)模式这3种自主控制依赖关系注入的方法来说,控制从根本上发生了倒转,这也正是控制反转(Inversion of Control, IoC) 名字的由来。 

Spring的IOC关键配置

1.如何定义(创建)一个bean

Spring IoC容器将管理一个或多个bean,这些bean 将通过配置文件中的bean定义被创建(在XML格式中为<bean/> 元素)。

在容器内部,这些bean定义由BeanDefinition 对象来表示,该定义将包含以下信息:

  • 全限定类名:这通常就是已定义bean的实际实现类。
  • bean行为的定义,这些定义将决定bean在容器中的行为(作用域、生命周期回调等等)
  • 对其他bean的引用,这些引用bean也可以称之为协作bean(collaborators) 或依赖bean(dependencies).
  • 创建bean实例时的其他配置设置。比如使用bean来定义连接池,可以通过属性或者构 造参数指定连接数,以及连接池大小限制等。

上述内容直接被翻译为每个bean定义包含的一组properties。具体的properties属性参考下面的:Spring官方的翻译文档;

2.bean如何实例化

从本质上来说,bean定义描述了如何创建一个或多个对象实例。当需要的时候, 容器会从bean定义列表中取得一个指定的bean定义,并根据bean定义里面的配置元数据 使用反射机制来创建(或取得)一个实际的对象。

当采用XML描述配置元数据时,将通过<bean/>元素的 class属性来指定实例化对象的类型。class 属性 (对应BeanDefinition实例的 Class属性)通常是必须的(不过也有两种例外的情形,见 Section 3.2.3.2.3, “使用实例工厂方法实例化”和 Section 3.6, “bean定义的继承”)。class属性主要有两种用途 :在大多数情况下,容器将直接通过反射调用指定类的构造器来创建bean(这有点类似于 在Java代码中使用new操作符);在极少数情况下,容器将调用 类的静态工厂方法来创建bean实例,class 属性将用来指定实际具有静态工厂方法的类(至于调用静态工厂 方法创建的对象类型是当前class还是其他的class则无关紧要)。

实例化主要有三种方式:用构造器来实例化,使用静态方法实例化,使用实例工厂来实例化;

3.DI-注入依赖(指的就是对象与对象之间的依赖关系通过配置的方式建立) 通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。DI主要有两种注入方式,即 Setter注入和 构造器注入;

3.1(Setter)首先是一个用XML格式定义的Setter DI例子。相关的XML配置如下:

<bean id="exampleBean" class="examples.ExampleBean">

  <!-- setter injection using the nested <ref/> element -->
  <property name="beanOne"><ref bean="anotherExampleBean"/></property>

  <!-- setter injection using the neater 'ref' attribute -->
  <property name="beanTwo" ref="yetAnotherBean"/>
  <property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>      
public class ExampleBean {

    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;

    public void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public void setIntegerProperty(int i) {
        this.i = i;
    }    
}      

3.2(构造器参数的方式)正如你所看到的,bean类中的setter方法与xml文件中配置的属性是一一对应的。接着是构造器注入的例子:

<bean id="exampleBean" class="examples.ExampleBean">

  <!-- constructor injection using the nested <ref/> element -->
  <constructor-arg>
    <ref bean="anotherExampleBean"/>
  </constructor-arg>
  
  <!-- constructor injection using the neater 'ref' attribute -->
  <constructor-arg ref="yetAnotherBean"/>
  
  <constructor-arg type="int" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>      
public class ExampleBean {

    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private int i;
    
    public ExampleBean(
        AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
        this.beanOne = anotherBean;
        this.beanTwo = yetAnotherBean;
        this.i = i;
    }
}      

4.Bean的生命周期回调 在Bean的创建之前或销毁的时候,我们可能做一些初始化处理或者释放资源的操作;

Spring提供了几个标志接口(marker interface),这些接口用来改变容器中bean的行为;它们包括InitializingBean和DisposableBean。实现这两个接口的bean在初始化和析构时容器会调用前者的afterPropertiesSet()方法,以及后者的destroy()方法。 

Spring在内部使用BeanPostProcessor实现来处理它能找到的任何标志接口并调用相应的方法。如果你需要自定义特性或者生命周期行为,你可以实现自己的 BeanPostProcessor。关于这方面更多的内容可以看Section 3.7, “容器扩展点”。

以上仅仅是我基于学习Spring官方翻译文档的一些关键内容记录,具体的学习请参考官方翻译文档

参考:

Spring官方翻译文档:http://shouce.jb51.net/spring/beans.html