b spring的ioc概念简单介绍

–> go to 总目录

什么是依赖注入与控制反转?

原文
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) principle. IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.
理解
依赖注入
首先容器(IOC container)是spring 最基础的单元。IOC也就是DI依赖注入,创建一个bean时,这个bean往往会有一堆依赖,spring的解决办法是,将这些依赖实例化,然后被bean所依赖。想象一个类,实例化时需要很多依赖的类实例,但是往往又不能每个都创建一次,但是如果将每个类都实例化,被依赖的类只需要保留一个对依赖类的句柄,主类实例化时将依赖的实例注入进去也就完成了实例化,这个实例化的类也成为一个新的容器,被其他类所依赖。
控制反转
试想一下,java中new一个实例,首先需要import 类的路径 比如import java.lang.String,然后使用它的构造器。也就是控制或定位类的实例靠类的路径或者构造器的方法签名。IOC中,每个容器都有自己的名字name,通过这个name反找出类的全路径,或者实例。这个过程是相反的。

1、介绍Spring IoC container和 Beans

org.springframework.beansorg.springframework.context是IOC的基础。BeanFactory接口提供了配置和管理组件的,ApplicationContext是BeanFactory的子接口,它添加了

  • 和Spring AOP特性更便捷的集成
  • 消息资源的处理(初始化时使用)
  • 事件发布
  • 应用层更具体的容器例如WebApplicationContext
    简短的讲,BeanFactory提供了框架和基础的功能。ApplicationContext添加了更多企业化的功能,是一个完善的BeanFactory超级集合仅仅被用来在这个章节里描述IoC容器,更多的是使用BeanFactory来讲解。
    在Spring中,一系列被IoC 容器管理的对象被称为beans。一个bean是一个可以被实例化、聚合或者被IoC容器管理的对象。

2、container 总览

接口org.springframework.context.ApplicationContext代表了IoC容器,并且负责管理beans。
容器获取自身关于什么对象被实例化、配置和聚合依赖读取元数据信息。这个元数据信息的格式有XML、java注解、java代码。元数据信息能充分表达对象之间的组合关系。
有几个关于ApplicationContext实现。独立应用模式,通常用
ClassPathXmlApplicationContextFileSystemXmlApplicationContext。当XML被用来当做配置元数据的信息的格式,你可以用一个小的xml文件来配置注解和代码的关系。
大多数场景情况下,无需我们自己定义xml文件,例如web项目生成时有web.xml。
下图是展示spring如何工作:应用的类(pojos)和配置信息(metadata)联合起来,
ApplicationContext 被创建和初始化后,你就有一个完整的容器系统被使用。
在这里插入图片描述

2.1 Configuration Metadata

spring的配置,spring传统是基于xml配置。
总共有三种配置方式

  • 基于xml。见下
  • 基于注解。见下 spring 2.5开始支持
  • 基于java code代码。见下 spring 3.0开始支持

xml<beans>标签为顶层容器,<bean>为元素。注解以@Cofiguration为容器,@Bean为元素。
定义的这些bean用来拼凑你的应用。典型的,你定义service layer的对象,data access objects(DAOS)数据模型,持久化
presentation对象例如Struts的Action对象,所使用框架的对象infrastructure objects例如Hibernate SessionFactories, JMS Queues。典型的你不能定义一些domian对象,他们依赖DAO和业务逻辑去生成和加载

domian对象,跟业务逻辑相关的动态对象,确切的信息生成确切的对象

xml格式的实例
但是你可以使用Spring 集成的AspectJ
去配置和管理IOC之外呢的对象。
在这里插入图片描述

  • id 属性标识独立bean的定义
  • class 具体说明类的全路径名称

2.2 Instantiating a Container

实例化一个容器。
ApplicationContext的构造函数支持的一个或多个paths路径来加载上述的configuration 数据,可以是本地文件系统,或者java的classpath等
形如

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
  • 服务层对象的配置
    service layer objects(services.xml)

在这里插入图片描述

  • DAO对象的配置

在这里插入图片描述

基于xml-based配置数据

在这里插入图片描述
可以使用构造器一次性的加载多个xml文件,也可以使用汇聚多个xml到一个文件。要注意services.xml和做import的文件位于同一目录,且最好使用相对路径而不是以’/'开头的路径,也不推荐用..

2.3、使用容器

ApplicationContextinterface是一个高级的工厂容器,包含不同的beans和他们的依赖。通过使用T getBean(String name,Class<T> requiredType)
获取beans
获取定义的beans
在这里插入图片描述
比较包容的用法
这种方式可以混合使用
在这里插入图片描述
或者加载grovy格式的配置文件
在这里插入图片描述

虽然提供了getBean,但是你的应用不应该使用getBean方式,否则就对spring的API产生了依赖。

3. bean 总览

一个spring的容器(Context)管理了很多bean。
对于容器自身来说,这些bean被BeanDefinition对象所代表。其包含了下列的元数据。

  • A package-qualified class name: bean实际上的实现类

  • Bean behavioral configuration elements:bean的行为配置,这个bean在容器中的行为(scope, lifecycle callbacks, and so forth).

  • References to other beans that are needed for the bean to do its work. 依赖类的句柄,其依赖信息的定义

  • 其他配置信息,例如连接池的size

bean的属性表

元数据信息由一系列的属性组成,下面就是这个表。

Property在XXX中解释
ClassInstantiating Beans
NameNaming Beans
ScopeBean Scopes
Constructor argumentsDependency Injection
PropertiesDependency Injection
Autowiring modeAutowiring Collaborators
Lazy initialization modeLazy-initialized Beans
Destruction methodDestruction Callbacks

当然用户也可以自己去实现ApplicationContextinterface来定义如何去生成和加载一个bean。这个是通过ApplicationContext的BeanFactory–getBeanFactory()方法获取,默认返回DefaultListableBeanFactory。DefaultListableBeanFactory支持registerSingleton(…) 和registerBeanDefinition(…)方法加载bean。

3.1 Naming Beans

每个bean都有一个或多个标识。这些标识必须在容器中是独一无二的。通常只有一个,如果要求多个,那么多余的就被当做别名。
xml-based可以使用idname属性,或者一起作为bean的标识。id一般是字母组成(‘myBean’,‘someService’),如果想有别名,请标记在name属性中,使用,;或空格分割。请注意id必须是独一无二的。
spring不要求一定要为bean配置id和name。容器会自动为bean生成一个。
如果想去引用一个bean,可以通过ref元素或者Service Locator风格。

在bean的定义之外重命名一个bean

一次性命名多个别名
在这里插入图片描述
可以兼容不同容器。

如果你使用注解 @Bean支持设置别名

3.2 实例化Beans

定义一个bean本质上是为了创建一个或多个对象。当一个bean被需要时,容器就会根据bean的定义来寻找这个或创建一个bean。
如果你用xml-based来配置元数据。那么class配置的信息会被设置在上文的BeanDefinitionclass属性里。
你可以用两种方式使用Class属性。

  • 典型的,容器利用反射调用class的构造器,等同于使用new
  • 或者具体指明是静态工厂static方法去创建实例。使用静态工厂方法创建的类,也许是一个sington或者是全新的实例

inner class names
内部类,如果你想去定义一个有static嵌套的内部类,你必须使用嵌套类的二进制名称。
比如你有一个类叫SomeThingcom.example包下,SomeThing里有静态类OtherThing,那么这个OtherThingclass属性值应该是**com.example.SomeThing O t h e r T h i n g ∗ ∗ 注 意 用 OtherThing**注意用 OtherThing符号来分割。

使用构造器来实例化

spring支持最好的就是构造器方法,推荐给类一个默认勾走方法。带有参数的构造器请详见后面依赖的注入
在这里插入图片描述

使用静态工厂方法实例化

要声明具体的静态方法类是什么。下面的xml指明了静态方法。
在这里插入图片描述

实例的静态工厂方法

首先实例化具体的工厂类。
factory-bean
factory-method来指明实例化的方法。可以有多个
在这里插入图片描述

4 dependencies

4.1 DI 依赖注入

依赖注入是指对象事先定义了内部属性,这些属性同过构造器的传参或者工厂方法,属性设置方法将实例和定义的内部属性关联。
DI原则的代码十分干净和有效。并且当内部属性是interface和abstract时,十分便于mock测试。
DI有两种方式

  • 基于构造器:constructor-based
  • 基于set方法:setter

constructor-based注入

单纯依赖构造器
在这里插入图片描述

Constructor Argument 构造器参数的解决

在这里插入图片描述
展示了利用<constructor-arg/>元素注入参数
在这里插入图片描述
当注入的参数属性类型和值是已知的简单类别时,靠<value>true</value>注入
相关类
在这里插入图片描述
参数类型match
在这里插入图片描述
参数索引match
在这里插入图片描述
以0开始
参数名称match
在这里插入图片描述

注解
可以使用JDK注解@ConstructorProperties来进一步指明构造器参数的名称,以便容器方便找到
在这里插入图片描述

setter-based DI set方法注入

下面是一个完全基于set方法的注入类
在这里插入图片描述
ApplicationContext支持constructor-based和setter-based DI混合。也支持是在constructor-based设置之后额外使用使用setter-based方法设置。
BeanDefinition格式装配依赖时,可以使用PropertyEditor转化propertie的格式。大多数spring的使用者并不会直接用这些类配置(除了xml),使用注解@Component, @Controller,或者基于@Configuration的@Bean,这些注解内部会转换成BeanDefinition属性并加载一个完整的Spring Ioc容器实例。

constructor-based或者setter-based DI
由于可以混用c-based和s-based,提倡对于必要的属性使用c-based,可选属性使用s-based。注意使用@Required注解在一个setter方法上可以指明为必要。
spring team推荐使用c-based DI,因为可以迅速得到一个可用的对象并确保属性不为null。要注意一个构造器有太多函数是一种坏味道,合理分离。
s-based DI应主要用于可选的依赖性,并设默认值。

依赖解决过程描述

容器解决bean依赖过程如下

  • ApplicationContext的创建和初始化依赖configuration metadata–描述了所有的beans。元数据配置格式可以是xml、java code、annotations
  • 对于每个bean,其依赖记录在在bean的一堆属性、构造器参数、或者工厂方法的参数中。这些依赖会在生产这个bean时被提供。
  • 每个属性或者构造器参数是一个具体的值或者另一个bean的引用句柄。
  • 每个属性或者构造器参数的值会被转化为定义的类型。默认可以转化的类型只有内置类型
    int、long、String、boolean等等。

当容器被创建时,spring容器会验证每个bean的配置。然而,在bean被创建出来之前bean的属性是不会被set的。singleton-scoped域下的Bean会在容器创建时创建。
其他的bean会在需要时创建,创建时依赖的类会被先创建。

循环依赖问题
抛出BeanCurrentlyInCreationException

DI示例

  • setter-basedxml配置示例
    在这里插入图片描述
    相关的类
    在这里插入图片描述
  • constructor-based配置示例
    在这里插入图片描述
    相关的类
    在这里插入图片描述
  • 静态工程方法的配置
    在这里插入图片描述
    相关的类
    在这里插入图片描述

4.2 Dependencies and Configuration in Detail

配置细节,上一节学会setter和constructor参数的配置,这一届细讲<property/><constructor-arg/>属性。

直接设置values

直接利用value设置属性值
在这里插入图片描述
p-namespace风格
在这里插入图片描述
也可以如下配置
在这里插入图片描述

idref

明确指明是和id匹配,在 or 中
在这里插入图片描述
等价于
在这里插入图片描述
会让container验证id对应的bean存不存在,第二种不会验证。

引用其他标签

ref元素在 or 中
一般情况下ref可以直接引用目标,先按找id找,找不到按name找。也是会检查bean存不存在。
在这里插入图片描述
但是存在不同容器下id相同的情况。比如你有一个层次化容器的设计。parent容器和sub容器有相同的id,这时用parent指明。
比如父容器中有个类id="accountService",子容器为了代理
"accountService"会有一个同名的类。
子容器的AOP是接受目标类参数,然后将自己设置为同名 ,这样就实现了代理。
在这里插入图片描述

inner bean

在这里插入图片描述
一个内部的类不能明确具体的ID或name,定义了容器也不能使用其值做识别。同样也会无视scope标记,也不可能被注入到其他bean中

集合Collections

,,和元素对应java的list,set,map和Properties。
截图中展示
在这里插入图片描述
在这里插入图片描述

集合合并

parent容器有集合,child容器也有自己的集合。child集合的结果是两者合并后的结果。
在这里插入图片描述
如上,child的 merage=true意味着child会继承parent属性,并覆盖相同的值。adminEmails最终的值为
在这里插入图片描述

集合合并的限制

不能合并不同的集合类型,否则会有Execption抛出

强类型集合

在这里插入图片描述
强类型会被赋值。

null和空String

在这里插入图片描述
等价于
在这里插入图片描述
对于空值
在这里插入图片描述
等价于
在这里插入图片描述

p-namespace风格

在这里插入图片描述

c-namespace风格

在这里插入图片描述

复合属性name

在这里插入图片描述
something有属性fred,fred有属性sammy,sammy有属性bob。

4.3 使用 depends-on

bean初始化的先后。
有些依赖关系并不直接,(直接的可以用ref),比如数据库的连接必须在DAO类初始化之前
在这里插入图片描述
depends-on表明,两个bean初始化顺序。

4.4 懒加载beans

ApplicationContext默认是希望所有的singleton bean作为初始化进程的一部分被加载,有错误也能被早发现。但是有时bean的行为不确定,不能预先确定加载那些bean,有些bean被请求时才会被加载。
在这里插入图片描述
not.lazy会被预先加载而lazy被使用时才会被加载。但是如果lazy被singleton依赖,也会被预先加载。
是否延时加载可以层级化控制,要配置在上
在这里插入图片描述

4.5 自动关联

spring Container可以自动建立bean的关联关系。自动关联有以下两个优点。

  • 可以显著减少对具体的属性或者构造器参数的需要
  • 当依赖升级时,自动关联可以升级配置。例如,如果你需要对一个class添加dependency,该依赖可以自动升级并且完全不用修改原先的配置。因此对开发中的变化多的情形有用,也完全不会对稳定不变的情形有坏处。

当使用XML-based配置,autoware属性可以配置在标签里。autowire有四种属性

模式解释
no默认不开启,bean的引用必须依赖ref
byName依赖property name,如果一个属性是master,他就会找setMaster(..)方法
byType依赖类型的匹配,如果有多个匹配就会报错
constructor类似byType,但是针对构造器参数

自动关联的缺点

  • 严格的依赖总能被property和constructor-arg设置满足。但是autowaire无法注入简单类型,比如String等
  • autowaire也没有以上两个描述的精确

排除Bean from Autowiring

使用autowire-candidate=false可以解决。

4.6 方法注入

大多数场景,大多数beans都是singleton模式。当一个singleton
需要和另一个singleton bean或者非singleton bean和一个singleton bean关联时,一般你需要定义一个为另一个的属性。但是当bean的生命周期不同时,问题就发生了。假设singleton bean A需要使用非singleton bean B–如果B的每个方法都被B调用。但是容器只会创造一次A,因此A只有一次机会去设置属性。容器不能提供给A一个新的B实例,当每次B被需要的时候。
一个可以的解决办法是放弃部分反转控制。你可以使A实现ApplicationContextAware接口,通过使用getBean(“B”)方法去每次通过容器来获取B实例来调用相关方法。
如下示例
在这里插入图片描述

寻找方法注入

Lookup method injection是一种容器的能力去返回指定bean的方法。典型的是涉及原型bean。

对于动态子类,子类或子类的方法不能为final修饰
单元测试abstract方法,的注入方法需要abstrace方法的实现方法
具体的方法被具体的类承载
lookup方法不能和工厂方法和@Bean修饰的方法放在一起。因为容器不能创建实例也不能在运行时生成子类

示例
在这里插入图片描述
抽象方法必须是如下的格式
在这里插入图片描述
方法注入如下
注意prototype,即用即创建如果是singleton,每次都返回同一个实例
在这里插入图片描述
等同于使用@Lookup注解
在这里插入图片描述
寻找MyCommand实例的createCommand方法。
也可以如下
在这里插入图片描述

进行随意的方法替换

xml-based可以使用replaced-method属性进行存在方法的替换。
示例
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
意味着replacementComputeValue的reimplemet方法会被当成computeValue方法。以上的xml配置会匹配方法签名为
在这里插入图片描述
的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值