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接口源码:
1 public interface BeanFactory { 2 3 //转定义符 4 String FACTORY_BEAN_PREFIX = "&"; 5 6 //定义5种获取Bean方法 7 Object getBean(String name) throws BeansException; 8 <T> T getBean(String name, Class<T> requiredType) throws BeansException; 9 <T> T getBean(Class<T> requiredType) throws BeansException; 10 Object getBean(String name, Object... args) throws BeansException; 11 <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; 12 13 //判断容器是否含有指定名字的Bean 14 boolean containsBean(String name); 15 16 //查询指定名字的Bean是否是Singleton类型的Bean. 17 boolean isSingleton(String name) throws NoSuchBeanDefinitionException; 18 19 //查询指定名字的Bean是否是Prototype类型的 20 boolean isPrototype(String name) throws NoSuchBeanDefinitionException; 21 22 //查询指定了名字的Bean的Class类型是否是特定的Class类型. 23 boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; 24 boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; 25 26 //查询指定名字的Bean的Class类型. 27 Class<?> getType(String name) throws NoSuchBeanDefinitionException; 28 29 //查询指定了名字的Bean的所有别名,这些都是在BeanDefinition中定义的 30 String[] getAliases(String name); 31 32 }
2.3 XmlBeanFactory实现类
spring3.1之后推荐直接使用:DefaultListableBeanFactory+XmlBeanDefinitionReader(第三节有样例)。虽然这个类已废弃,但不妨碍我们来简单理解一下
1 @Deprecated 2 @SuppressWarnings({"serial", "all"}) 3 public class XmlBeanFactory extends DefaultListableBeanFactory { 4 5 private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); 6 //载入资源构造 7 public XmlBeanFactory(Resource resource) throws BeansException { 8 this(resource, null); 9 } 10 //通过载入资源和父类的BeanFactory构造 11 public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { 12 super(parentBeanFactory); 13 this.reader.loadBeanDefinitions(resource); 14 } 15 16 }
1.在XmlBeanFactory中实例化了一个XmlBeanDefinitionReader,这个Reader对象就是用来处理以xml形式的持有类信息的BeanDefinitionl类。
2.BeanDefinitionl信息封装成Resource,作为构造入参
3.调用reader的loadBeanDefinitions,完成容器的初始化和注入。
2.4 模拟容器获取Bean
1 public static void main(String[] args) { 2 //1.容器IOC获取bean初始化 3 ClassPathResource resource = new ClassPathResource("spring.xml");//载入资源 4 DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); 5 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);//构造reader 6 reader.loadBeanDefinitions(resource);//核心方法,解析bean定义 7 Dao dao = factory.getBean("daoImpl", Dao.class);//IOC容器DefaultListableBeanFactory通过名称和类class获取bean单例对象 8 dao.select();//执行Bean实例方法 9 }
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
如果你觉得本文对你有点帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!