一、Spring IoC原理

主要内容

1、IoC和DI的概念

2、IoC容器概述

3、IoC容器的初始化

4、依赖注入过程

5、Bean的生命周期

 

一、IoC和DI概念

IoC:Inverse of Control(控制反转):将原本在对象中依赖对象创建的控制权,交由Spring IoC容器创建管理。

DI:Dependency Injection(依赖注入):是IoC的另一种描述,指Spring管理对象的依赖关系,将对象依赖通过配置(构造器注入、Setter方法注入)然后再进行注入。

总结:Spring IoC容器的工作,管理对象生命周期和对象间依赖关系。


二、IoC容器概述

a、什么是IoC容器

从BeanFactory源码中了解到,大致就是管理对象的工厂,定义了基本获取对象的方法,和判断对象的某些特性的方法。

public interface BeanFactory {

    //对FactoryBean转义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象

    String FACTORY_BEAN_PREFIX = "&";

    //通过名称获取bena实例

    Object getBean(String name) throws BeansException;

    //按照类象获得Bean,requiredType可以是父类

    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

    //按照给定的参数创建bean实例(仅在创建新实例时才应用,而不是在检索现有实例时应用)

    Object getBean(String name, Object... args) throws BeansException;

    //根据类型获得Bean

    <T> T getBean(Class<T> requiredType) throws BeansException;

    //按照给定的参数创建对应的Bean(仅在创建新实例时才应用,而不是在检索现有实例时应用)

    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    //根据name判断,是否含有某个Bean

    boolean containsBean(String name);

    //是否单例Bean

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    //是否为原型Bean

    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    //检查bean是否和给定的类型匹配

    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    //获取Bean的Calss类型

    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    //获取Bean别名

    String[] getAliases(String name);

}

 

b、IoC容器有两个系列容器,接口是:BeanFactory系列和ApplicationContext系列

继承关系如下:

 

区别:为什么有BeanFactory还需要ApplicationContext,从接口依赖关系可以知道

1、支持不同的信息源:国际化支持。

2、资源访问:Resource rs = ctx. getResource(“classpath:a.properties”)或者“file:c:/a.properties”。

3、容器事件:监听容器的启动、刷新、停止、暂停。

 

c、常使用的IoC容器实现类

BeanFactory系列:

DefaultListableBeanFactory

XmlBeanFactory

 

ApplicationContext系列:

XmlWebApplicationContext

AnnotationConfigApplicationContext

AnnotationConfigWebApplicationContext

ClassPathXmlApplicationContext

FileSystemXmlApplicationContext


三、IoC容器的初始化

a、涉及接口说明

1、Resource接口,可以通用地访问文件资源。

2、ResourceLoader类用于载入Resource

3、BeanDefinition接口,是配置文件< bean >元素标签在容器中地内部表示。< bean >元素标签拥有class、scope、lazy-init等配置属性,BeanDefinition则提供了相应地beanClass、scope、lazyInit类属性与之相互对应。

 

b、初始化过程(三步骤)

简述:

1、定位:Resource定位。

2、载入:BeanDefinitionReader将Resource定位好的资源载入到BeanDefinition。

3、注册:BeanDefinitionRegistry将BeanDefiniton注册到容器(ConcurrentHashmap)中。

 

详细说明:

1、定位

Resource是Sping中用于封装I/O操作的接口。在创建spring容器时,通常要访问XML配置文件,除此之外还可以通过访问文件类型、二进制流等方式访问资源,还有当需要网络上的资源时可以通过访问URL,Spring把这些文件统称为Resource,常用的resource资源类型如下:

  1、FileSystemResource:以文件的绝对路径方式进行访问资源,效果类似于Java中的File;

  2、ClassPathResourcee:以类路径的方式访问资源,效果类似于this.getClass().getResource("/").getPath();

  3、ServletContextResource:web应用根目录的方式访问资源,效果类似于request.getServletContext().getRealPath("");

  4、UrlResource:访问网络资源的实现类。例如file: http: ftp:等前缀的资源对象;

  5、ByteArrayResource: 访问字节数组资源的实现类。

 

在资源定位过程完成以后,就为资源文件中的bean的载入创造了I/O操作的条件,如何读取资源中的数据将会在下一步介绍的BeanDefinition的载入过程中描述。

 

2、通过返回的resource对象,进行BeanDefinition的载入

  在Spring中配置文件主要格式是XML,以XML为例,对于用来读取XML型资源文件来进行初始化的IoC 容器而言,该类容器会使用到AbstractXmlApplicationContext类,该类定义了一个名为loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 的方法用于获取BeanDefinition

此方法在具体执行过程中首先会new一个与容器对应的BeanDefinitionReader型实例对象,然后将生成的BeanDefintionReader实例作为参数传入loadBeanDefintions(XmlBeanDefinitionReader),继续往下执行载入BeanDefintion的过程。例如AbstractXmlApplicationContext有两个实现类:FileSystemXmlApplicationContext、ClassPathXmlApplicationContext,这些容器在调用此方法时会创建一个XmlBeanDefinitionReader类对象专门用来载入所有的BeanDefinition。

该过程的最终结果就是将XML解析并转化为BeanDefinition。

 

3、将BeanDefiniton注册到容器

最终Bean配置会被解析成BeanDefinition并与beanName,Alias一同封装到BeanDefinitionHolder类中, 之后beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition()),注册到DefaultListableBeanFactory.beanDefinitionMap中。之后客户端如果要获取Bean对象,Spring容器会根据注册的BeanDefinition信息进行实例化。

public class DefaultListableBeanFactory

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(64);


四、依赖注入过程

a、简述:

发生依赖注入的启动为getBean方法,该方法做的就是创建对象和正确的设置好依赖关系,以及初始化(调用一些初始化方法)。

也可以通过lazy-init属性控制Bean的依赖注入时机。当lazy-init=true时,依赖注入会发生在第一次向容器获取Bean时(getBean);当lazy-init=false时,会在容器初始化的过程中将所有的singleton bean提前进行实例化和依赖注入,因此singleton bean的依赖注入是容器初始化过程的一部分,这也是ApplicationContext的默认配置,BeanFactory的默认配置是true。

 

b、简单流程

1、以DefaultListableBeanFactory为例,其基类AbstractBeanFactory中实现了getBean方法,getBean中调用了doGetBean。

 

2、doGetBean方法中。在获取Bean时,先从缓存中能取得Bean,如果取得那些已经被创建过的Singleton的Bean,对这种Bean的请求不需要重复创建,直接返回。如果缓存中不能取得的话,并且有parentBeanFactory的话,就从parentBeanFactory中取,如果parentBeanFactory也有父容器,并且在当前父容器没找到就一直往上找,如果某层父容器中有的话,创建操作就在parentBeanFactory。如果parentBeanFactory中也取不到的话,那就根据Bean的类型(Singlton或Prototype或其它)去创建Bean(createBean方法)。

 

4、createBean这个方法有两个重要点首先创建Bean实例(createBeanInstance),然后进行依赖注入(populateBean),最后初始化Bean及调用的初始化方法(initializeBean)。

 

5、createBeanInstance方法通过适当的实例化策略来创建一个Bean实例。在这个过程中,通过默认构造方法(无参构造)是基本的实例化策略,这个策略Spring的实现中提供了两种创建Bean的方式:其一,通过JVM反射创建Bean实例;其二,通过cgLib动态代理创建Bean实例(默认)。

 

6、populateBean方法是对bean实例进行依赖关系设置,完成依赖注入过程。首先由InstantiationAwareBeanPostProcessors进行依赖注入前的处理,判断是否对Bean的Property进行注入,接下来先处理autowire的注入,这里的autowire指的是在配置文件中通过autowire="byName"或者autowire="byType"等属性配置的bean,最后处理Property属性注入。

 

7、initializeBean方法用于初始化Bean。调用的初始化方法如下:

1、如果Bean实现了Aware系列的接口的话,调用这些接口的实现。

2、对BeanPostProcessor后置处理器的postProcessBeforeInitialization和postProcessAfterInitialization 回调方法的调用,为Bean实例初始化之前和之后做一些处理。

3、调用Bean实例对象初始化的方法,这个初始化方法是在Spring Bean定义配置文件中通过init-method属性指定的。

 

8、Bean的预实例化。当为Bean配置了lazy-init=false属性时,IOC容器会在初始化的时候对Bean进行预实例化,这时将会提前触发Bean的依赖注入过程,回到AbstractApplicationContext的refresh方法中,这里是IOC容器初始化的入口,在这个方法中调用了finishBeanFactoryInitialization方法,这个方法将会对非延迟加载的单例Bean进行预实例化。在预实例化的过程中调用了getBean方法来触发Bean的依赖注入,后续的处理与前面分析的过程一样,通过一系列的处理,Bean的预实例化过程就完成了。

 

9、这样就完成了依赖注入过程。该Bean以及Bean之间的依赖关系建立完成以后,通过IoC容器的相关接口方法,就可以提供给上层应用使用了。

 

五、Bean的生命周期

1、实例化一个Bean,可以理解为new,当然不是new那么简单而是通过反射或者Cglib(默认);

2、按照Spring上下文对实例化的Bean进行配置,也就是IOC注入;

 

以下是一系列Aware回调接口,用于获取IoC容器的一些信息

3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值

4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);

5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);

 

6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化之前调用的方法,也可以被应用于内存或缓存技术;

 

7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。

 

8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;

 

9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法或者如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值