Spring ioc源码解析这一系列文章会比较枯燥,但是只要坚持下去,总会有收获,一回生二回熟,没有第一次,哪有下一次...

本系列目录:

Spring IOC(一)概览

Spring IOC(二)容器初始化

Spring IOC(三)依赖注入

Spring IOC(四)总结

一、Spring IOC概述

1.1 IOC

Ioc—Inversion of Control,即“控制反转”,是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

  ●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

  ●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

  用图例说明一下,传统程序设计都是主动去创建相关对象然后再组合起来,如下图:

当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了,如下图:

1.2 DI

DI—Dependency Injection,即“依赖注入”组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

  理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

  ●谁依赖于谁:当然是应用程序依赖于IoC容器

  ●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源

  ●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象

  ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)

1.3 IOC和DI关系

  IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

二、核心类源码解读

2.1 Spring IOC容器接口设计

Spring框架中,一旦把一个bean纳入到Spring IoC容器之中,这个bean的生命周期就会交由容器进行管理,一般担当管理者角色的是BeanFactory或ApplicationContext。下面来看一下IOC容器接口设计,如下图(默认JDK8):

如上图,可见主要有两条主线

  1.基本容器:BeanFactory-》HierarchicalBeanFactory-》ConfigurableBeanFactory

  • BeanFactory接口定义了基本的Ioc容器的规范,包括getBean()这样的Ioc容器的基本方法(通过这个方法可以从容器中取得Bean)。
  • HierarchicalBeanFactory增加了getParentBeanFactory()的接口功能,使BeanFactory具备了双亲Ioc容器的管理功能。
  • ConfigurableBeanFactory定义了一些配置功能,比如通过setParentBeanFactory()设置双亲Ioc容器,通过addBeanPostProcessor()配置Bean后置处理器,等等。

  2.高级容器:BeanFactory-》ListableBeanFactory-》ApplicationContext-》WebApplicationContext/ConfigurableApplicationContext

  • ListableBeanFactory细化了许多BeanFactory的接口功能,比如定义了getBeanDefinitionNames()接口方法;
  • ApplicationContext接口,它通过继承MessageSource、ResourcePatternResolver、ApplicationEventPublisher接口,在BeanFactory简单Ioc容器的基础上添加了许多对高级容器的特性支持。

2.2 BeanFactory接口

尊重源码,以下摘自BeanFactory源码注释翻译:

BeanFactory是获取spring bean容器的顶级接口。该接口被持有一系列bean definitions的对象所实现。依赖bean definitions,工厂返回一个原型实例或者一个单例实例。
通常,BeanFactory将加载存储在配置中的bean definitions资源(例如XML文档)。这些定义没有限制何种方式存储:LDAP, RDBMS, XML,properties file等。并且鼓励使用bean的依赖注入引用。

实现类需要支持Bean的完整生命周期,完整的初始化方法及其标准顺序(格式:接口 方法)为:

1.BeanNameAware setBeanName 设置bean名称
2.BeanClassLoaderAware setBeanClassLoader 设置bean类加载器
3.BeanFactoryAware setBeanFactory 设置bean工厂
4.EnvironmentAware setEnvironment 设置环境:profiles+properties
5.EmbeddedValueResolverAware setEmbeddedValueResolver 设置嵌入式值解析器
6.ResourceLoaderAware setResourceLoader 设置资源载入器,只适用于在应用程序上下文中运行
7.ApplicationEventPublisherAware setApplicationEventPublisher注入应用事件发布器ApplicationEventPublisher
8.MessageSourceAware setMessageSource 设置国际化支持
9.ApplicationContextAware setApplicationContext 设置应用上下文
10.ServletContextAware setServletContext 设置servlet上下文
11.BeanPostProcessors postProcessBeforeInitialization 执行bean处理器前置方法
12.InitializingBean afterPropertiesSet 执行初始化Bean设置完属性后置方法
13.a custom init-method definition 执行自定义初始化方法
14.BeanPostProcessors postProcessAfterInitialization 执行bean处理器后置方法

销毁顺序:
1.DestructionAwareBeanPostProcessors postProcessBeforeDestruction 销毁处理器的前置方法
2.DisposableBean destroy Bean销毁回调方法
3.a custom destroy-method definition 用户自定义销毁方法

关于Spring bean 生命周期的验证,飞机票:Spring bean 生命周期验证

下面来看一下BeanFactory接口源码:

 public interface BeanFactory {

     //转定义符
String FACTORY_BEAN_PREFIX = "&"; //定义5种获取Bean方法
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException; //判断容器是否含有指定名字的Bean
boolean containsBean(String name); //查询指定名字的Bean是否是Singleton类型的Bean.
boolean isSingleton(String name) throws NoSuchBeanDefinitionException; //查询指定名字的Bean是否是Prototype类型的
boolean isPrototype(String name) throws NoSuchBeanDefinitionException; //查询指定了名字的Bean的Class类型是否是特定的Class类型.
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; //查询指定名字的Bean的Class类型.
Class<?> getType(String name) throws NoSuchBeanDefinitionException; //查询指定了名字的Bean的所有别名,这些都是在BeanDefinition中定义的
String[] getAliases(String name); }

2.3 XmlBeanFactory实现类

spring3.1之后推荐直接使用:DefaultListableBeanFactory+XmlBeanDefinitionReader(第三节有样例)。虽然这个类已废弃,但不妨碍我们来简单理解一下

 @Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
//载入资源构造
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
//通过载入资源和父类的BeanFactory构造
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
} }

1.在XmlBeanFactory中实例化了一个XmlBeanDefinitionReader,这个Reader对象就是用来处理以xml形式的持有类信息的BeanDefinitionl类。

2.BeanDefinitionl信息封装成Resource,作为构造入参

3.调用reader的loadBeanDefinitions,完成容器的初始化和注入。

2.4 模拟容器获取Bean

 public static void main(String[] args) {
//1.容器IOC获取bean初始化
ClassPathResource resource = new ClassPathResource("spring.xml");//载入资源
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);//构造reader
reader.loadBeanDefinitions(resource);//核心方法,解析bean定义
Dao dao = factory.getBean("daoImpl", Dao.class);//IOC容器DefaultListableBeanFactory通过名称和类class获取bean单例对象
dao.select();//执行Bean实例方法
}
spring.xml中就写一行:定义一个Bean即可
 <bean id="daoImpl" class="spring.aop.xml.dao.impl.DaoImpl" />

三、总结

本文概述IOC/DI 原理并分析了Spring核心接口设计,最后结合一个简单例子,模拟了最简单的容器DefaultListableBeanFactory从xml载入bean定义并生成bean对象的过程让大家有一个大体的认知。

下一章,我们将分析容器初始化。

=======================

参考

http://www.zzcode.cn/springioc/thread-39.html

谈谈对Spring IOC的理解

Spring 源码剖析IOC容器(一)概览的更多相关文章

  1. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  2. Spring源码解析-IOC容器的实现-ApplicationContext

    上面我们已经知道了IOC的建立的基本步骤了,我们就可以用编码的方式和IOC容器进行建立过程了.其实Spring已经为我们提供了很多实现,想必上面的简单扩展,如XMLBeanFacroty等.我们一般是 ...

  3. Spring源码解析-IOC容器的实现

    1.IOC容器是什么? IOC(Inversion of Control)控制反转:本来是由应用程序管理的对象之间的依赖关系,现在交给了容器管理,这就叫控制反转,即交给了IOC容器,Spring的IO ...

  4. SPRING源码分析:IOC容器

    在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定 - 不管怎么着,作为IOC容器,这些接口你必须要满足应用程序的最基本要求: ...

  5. Spring源码阅读-IoC容器解析

    目录 Spring IoC容器 ApplicationContext设计解析 BeanFactory ListableBeanFactory HierarchicalBeanFactory Messa ...

  6. spring 源码之 ioc 容器的初始化和注入简图

    IoC最核心就是两个过程:IoC容器初始化和IoC依赖注入,下面通过简单的图示来表述其中的关键过程:

  7. Spring源码之IOC容器创建、BeanDefinition加载和注册和IOC容器依赖注入

    总结 在SpringApplication#createApplicationContext()执行时创建IOC容器,默认DefaultListableBeanFactory 在AbstractApp ...

  8. 转 Spring源码剖析——核心IOC容器原理

    Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...

  9. spring源码浅析——IOC

    =========================================== 原文链接: spring源码浅析--IOC   转载请注明出处! ======================= ...

随机推荐

  1. 201521123057 《Java程序设计》第13周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...

  2. 201521123012 《Java程序设计》第十三周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec ...

  3. Markdown格式范例

    一个例子: 例子开始 1. 本章学习总结 今天主要学习了三个知识点 封装 继承 多态 2. 书面作业 Q1. java HelloWorld命令中,HelloWorld这个参数是什么含义? 今天学了一 ...

  4. PHP面向对象简单总结

    类和对象对象:一切东西都可以看做对象,对象是类的实例化.类:类是对象的抽象,用来描述众多对象共有的特征. 定义类 class成员变量 和 成员方法访问修饰符 public共有的 private 私有的 ...

  5. json:JSONObject包的具体使用(JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包)

    1.JSONObject介绍 JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包. 2.下载jar包 http:// ...

  6. firebug离线安装方法-拖入法

    这里介绍的是如何在Firefox中离线安装firebug插件. 1, 下载firebug离线包, 一般就是一个*.xpi文件; 2, 打开Firefox浏览器,直接将*.xpi文件拖入Firefox浏 ...

  7. session get和load方法对比

    get测试代码如下: public class Test { public static void main(String[] args) { // TODO Auto-generated metho ...

  8. Android 之JDBC

    JDBC(Java DataBase Connectivity)是使用 Java 存取数据库系统的标准解决方案,它将不同数据库间各自差异API与标准 SQL语句分开看待,实现数据库无关的 Java操作 ...

  9. (转)Unity3D 之插值计算

    在unity3D中经常用线性插值函数Lerp()来在两者之间插值,两者之间可以是两个材质之间.两个向量之间.两个浮点数之间.两个颜色之间,其函数原型如下: Material.Lerp 插值 funct ...

  10. NSTimer、CADisplayLink 内存泄漏

    NSTimer.CADisplayLink 内存泄漏 内存泄漏的原因 CADisplayLink 要用 Taget 和 Selector 初始化,NSTimer 也可以用类似的方法初始化.这样初始化之 ...