全文是Inversion of Control。翻译过来就是控制反转,意思是对象之间的关系不再由传统的程序来控制,而是由spring容器来统一控制这些对象创建、协调、销毁,而对象只需要完成业务逻辑即可。
可以看出ioc主要是通过spring容器来维护bean的生命周期(从创建到销毁),同时也会包含DI(注入依赖)等bean对象填充的操作。接下来我们重点通过源码来看下bean是如何被定义,被创建,以及初始化和销毁的。
我们先抛开spring代码实现,自己思考几分钟;如果让你去做个spring容器的话,有哪些事你肯定是要做的。
在我们跟源码之前,我觉得有必要先写一下关于Spring的IOC的核心类以及它的关系图是怎样的,这样可以让我们对spring有个更上层面和清晰的了解。
registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
我们先启动一个Spring容器
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
@Configuration
@ComponentScan(basePackages = {"com.yan.ioc.service"})
public class MainConfig {
@Bean
public ConfigBean configBeanA() {
return new ConfigBean();
}
@Bean
public ConfigBean configBeanB() {
return configBeanA();
}
}
AnnotationConfigApplicationContext是Spring提供给我们管理ioc容器直接调用的入口类,传入的参数为我们javaconfig配置类的class。
它负责了Bean的注册以及生命周期的管理,同时它还包括了国际化,事件管理等其它的功能。之于它为什么可以完成这么多的事,我们不妨先看看它到底继承了哪些重要的类。
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry
首先看到AnnotationConfigApplicationContext的继承了GenericApplicationContext
GenericApplicationContext:Spring对configurableeListableBeanfactory的默认实现和BeanDefinitionRegistry接口:一个成熟的bean工厂基于bean定义元数据,可通过后处理器扩展。
GenericApplicationContext实现了BeanDefinitionRegistry bean定义注册接口,那它是如何实现的呢。
它用到了装饰模式,并在装饰模式里new了DefaultListableBeanFactory,而DefaultListableBeanFactory才是真正做到实现BeanDefinitionRegistry接口的类。
public GenericApplicationContext() {
/**
AnnotationConfigApplicationContext被new的同时,因为它是父类,
它直接创建了个DefaultListableBeanFactory,这个玩意是不是很眼熟
对它就是我们经常说到或者用到的BeanFactory了!!!
*/
this.beanFactory = new DefaultListableBeanFactory();
}
我们再看看DefaultListableBeanFactory的结构
从图中可以看到DefaultListableBeanFactory是个非常底层的类了,也是一个具有强大功能的类,它也是我们通常说的BeanFactory。
我们直接在DefaultListableBeanFactory类了发现了beanDefinitionMap这个集合,貌似是用来存放BeanDifiniton的,key应该是beanName; 这里我们完全可以做一个大胆的假设,spring扫描javaconfig配置类后,解析出来的所以bean定义信息全部都存放在这里了。
通过DefaultListableBeanFactory的关系图,我们还知道它继承了AbstractApplicationContext
springframework.context的抽象实现ApplicationContext接口。不强制配置使用的存储类型;简单地实现公共上下文功能。使用模板方法设计模式,需要具体的子类来实现抽象方法。
它是一个模板类,换句话说它定义了很多方法,我们都是可以直接用的(而且是经常会用到的);只不过它可能会抛出来几个抽象的钩子方法让子类去实现。那我们来看看它到底有那些你一定见过的方法呢。
大家一直说refresh方法,那refresh方法到底在哪里呢,它在AbstractApplicationContext这个模板类里;基本上我们对javaconfig配置类的解析,bean的扫描,注册以及实例化,属性填充,初始化都是在这里完成,当然国际化,事件管理也在这里实现的。
那这个模板类有留出了个什么钩子方法呢?
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
看到上面代码就明白了,GenericApplicationContext装饰了实现了BeanDefinitionRegistry接口的DefaultListableBeanFactory类;然后它又继承了模板类AbstractApplicationContext,把DefaultListableBeanFactory这个又回调给了AbstractApplicationContext。
核心类与结构我们大致清晰了,那我们再回到AnnotationConfigApplicationContext类来。如果spring要做ioc容器管理,最起码要做两件事情。
Bean的扫描与注册: 加载javaconfig配置类文件,解析它的扫描包(componentScan),安装扫描包递归解析,最后存放到一个配置类集合里。
创建与管理Bean:拿出配置类集合,进行实例化,属性填充(@Autowire等),以及初始化。
这里我画了个Spring ioc容器实现原理的脑图,看不清的可以到processon上创建的项目里去看,密码:Phn3
其实如果你对spring里各种后置处理器很了解的话,我想直接看这个脑图是没有问题的。如果没有深入了解也没关系,接下来我将拿几个核心的后置处理器进行讲解。
后置处理器主要分两大类:
再讲解后置处理器之前,还是有必要先说下spring的一个重要思想,不然你自己再去跟源码可能会晕乎乎的。
spring万物皆bean
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessor同时继承了BeanFactoryPostProcesser接口,BeanFactoryPostProcesser的主要目的是修改Bean定义,所以BeanDefinitionRegistryPostProcessor通知具备注册和修改Bean定义的功能。
ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,并且Spring将它注册到了容器里。ConfigurationClassPostProcessor这个类非常重要,我们先把流程理清楚。
为什么我们直接通过AnnotationConfigApplicationContext就能把ConfigurationClassPostProcessor注册到容器里呢。(可以参考GenericApplicationContext与BeanFactory小节同时理解)
我们首先要扫描Bean呀,不扫描哪来的注册呢?ConfigurationClassPostProcessor就起到了扫描与注册Bean的关键作用,下面这张图诠释了ioc扫描与注册容器的过程。
Bean的生命周期大概分为这四大步,但是Spring又分别在其中加入了后置后处理器的处理。 它的整个过程是发生在**refresh()**方法里。
在Spring ioc的扫描与注册里,我们已经知晓了两个后置处理器,分别是BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor ,它们主要是负责BeanDefinition的注册与修改,而在真正创建一个bean的时候,它又用到了如下几大类后置处理器
直接看名字,前缀是Instantiation,那一定是用在实例化的环节来使用。InstantiationAwareBeanPostProcessor继承了BeanPostProcessor, 所有这个接口处理实例化前后做处理,还有在初始化前后做处理的功能。比如AspectJAwareAdvisorAutoProxyCreator后置处理器就实现了InstantiationAwareBeanPostProcessor的接口。
spring容器在getBean去创建一个bean的时候,会去检查容器里是否有实现了InstantiationAwareBeanPostProcessor的注册bean,如果有的化则拿出来在其它bean的实例化前后其执行。
它有如下方法:
postProcessBeforeInstantiation(Class> beanClass, String beanName)
这个方法在实例化前处理,一般用于解析指定bean是否有切面,并缓存。
postProcessAfterInstantiation(Object bean, String beanName)
spring 留给我们的扩展接口:让用户可以自定义属性注入,若返回false,后面的一些的后置处理都不存在了,直接返回Bean
postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
比如AutowiredAnnotationBeanPostProcessor就实现了它,在属性填充的过程来完成bean的依赖注入。
ApplicationContextAwareProcessor实现了BeanPostProcessor,这个后置处理器主要用来给各种的aware传值
如果你设计的Bean实现了如上6个Aware,spring会调用ApplicationContextAwareProcessor.postProcessBeforeInitialization把对应aware想要的对象set进去。
spring ioc的流程大致可以分为两块,bean的扫描与注册,bean的创建
spring所有的功能实现的前提是:你把实现该功能的bean注册进来再说
ConfigurationClassPostProcessor是出来扫描和注册的关键bean,它会去解析配置类的@ComponentScan,@Import,然后扫描这些bean,打包成BeanDefiniton并注册到容器里。注意它并没有创建bean,只是注册到了容器里。
bean是通过BeanDefiniton类注册,BeanDefiniton定义的类的class,scope,primary,depends,isAutowire等。
bean的创建可以分为实例化,填充属性,初始化,销毁等阶段。只不过Spring在其中添加了一些后置处理器和aware
创建过程的后置处理器是实现了BeanPostProcessor接口的类,BeanPostProcessor分别提供初始化前和后的方法。
比如ApplicationContextAwareProcessor就实现了BeanPostProcessor接口,它主要用于初始化的前处理,把各种aware想要的对象set进去
而InstantiationAwareBeanPostProcessor继承了BeanPostProcessor,它同时为bean的实例化前后添加了方法。比如AutowiredAnnotationBeanPostProcessor就实现了它,主要用它的实例化后处理的方法来实现bean的依赖注入。
ApplitionContext装饰了BeanFactory,它相比BeanFactory多了国际化的支持,消息的处理,以及事件发布与监听的管理
BeanFactory和FactoryBean是两码子事,FactoryBean是用来修饰这个bean的实例化方法,它是一个工厂设计模式,通过getObject()的方法来返回实例。BeanFactory是来做bean的注册与创建的容器,高级多了。