容器的启动和实例化

SpringIoC容器实现以上功能的过程,基本上可以按照类似的流程划分为两个阶段,即容器启动阶段Bean实例化阶段

 

启动阶段:

refresh()方法启动(这个方法在IoC容器的具体实现类的构造函数中),启动包括

1BeanDefinitionResource定位(获取资源位置的Resource对象)

构造IoC容器时,需要指定BeanDefinition的信息来源(如从xml文件中来),而这个信息来源需要封装成spring中的Resource类来进行IO操作ResourceSpring用来封装I/O操作的类。Resource是一个接口,具体实现类如ClassPathResource。通过配置文件指定的文件位置完成BeanDefinition的定位,但具体的数据还没开始读入。

Resource只是BeanDefinition位置的封装,具体操作由ResourceLoader完成。这个过程即找到BeanDefinition的位置,为其载入创造I/O操作的条件。

  1. 构造函数调用refresh(),该方法在synchronized修饰的同步代码块中,保证不能有多个线程初始化。
  2. refresh()先调用createBeanFactory()创建容器
  3. refresh()再调用loadBeanDefinitions(BeanFactory)方法
  4. loadBeanDefinitions()先调用ResourceLoader得到Resource[]数组(定位)
  5. loadBeanDefinitions()再调用Reader读取器(如XMLBeanDefinitionReader)读取Resource[]中资源(完成I/O操作,即开始载入),利用回调把结果传入之前建立的BeanFactory

很多不同的类都有loadBeanDefinitions方法,它们的功能也是不同的。

 

2载入(解析xml配置文件,获取各个Element信息)

把用户定义好的Bean表示成IoC容器内部的数据结构(即BeanDefinition)。BeanDefinition的载入分两部分,首先调用XML解析器得到document对象,但这些document对象没有按照springbean规则进行解析。接下来按照spring规则进行解析。

  1. Reader读取器(如XMLBeanDefinitionReaderloadBeanDefinitions方法)中调用documentLoaderXML解析器)中的方法,获得document对象;

简单说就是:第一步通过XML解析器把xml文件中的信息解析成document对象(继承了Node本质是节点)。

  1. Reader读取器(如XMLBeanDefinitionReaderloadBeanDefinitions方法)再调用processBeanDefinition(传入documentelement);

简单说就是:第二步获取document对象各个element信息(继承了Node本质是节点)。

  1. processBeanDefinition (element,BeanDefinition)方法调用parseBeanDefinitionElement()方法,解析具体的元素标签(如<bean><name><id>等),将解析得到的结果设置到BeanDefinitionHolder中(BeanDefinitionHolderBeanDefinition对象的封装类,封装了BeanDefinitionbean的名字等,用它来完成向IoC容器注册);

简单说就是:第三步解析element中具体的元素标签到BeanDefinition中。

 

经过对document逐层解析,我们在XML中定义的BeanDefinition就被载入到了IoC容器中。但是,重要的依赖注入在这个时候还没有发生,现在IoC容器中BeanDefinition存在的还只是一些静态的配置信息

 

3、容器扩展机制

Spring提供了一种叫做BeanFactoryPostProcessor的容器扩展机制该机制允许我们在容器实例化相应对象之前,对注册到容器的BeanDefinition所保存的信息做相应的修改。这就相当于在容器实现的第一阶段最后加入一道工序,让我们对最终的BeanDefinition做一些额外的操作,比如修改其中bean定义的某些属性,为bean定义增加其他信息等。

 

4注册(将BeanDefinition放入concurrenthashmap中)

BeanDefinition放入HashMap中,这些BeanDefinition数据在IoC容器中通过一个concurrenthashmapConcurrentHashMap<String,BeanDefinition>)来保持和维护,beanNamekeybeanDefinitionvalue

  1. 在第上面最后一步processBeanDefinition()方法中调用registerBeanDefinition(BeanDefinitionHolder)开始注册,map.put(beanName,BeanDefinition),registerBeanDefinition中需要synchronized同步代码块,保证数据一致性。以上过程都是在Reader读取器类中完成的。

 

 

 

 

 

实例化阶段

 

1、初始化/实例化被请求对象,并为其添加属性。

2、其他处理

微观上:

1、当外部或直接调用getBean()方法后,通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或者动态生成其子类。并完成依赖注入

依赖注入的过程是用户第一次向IoC容器索要Bean时触发的(BeanFactory.getBean(name)),当然也有例外,也就是我们可以在BeanDefinition信息中通过控制lazy-init属性来让容器完成对Bean的预实例化(在初始化过程中完成,即在refresh()(初始化的入口)时调用getBean())。通过依赖注入生成实例。

  1. getBean()方法中,首先判断是否已经创建,且为单例,这种情况不要创建。然后根据Bean的名字获取BeanDefinition,当前取不到就到双亲BeanFactory中取,如果还取不到就顺着双亲链一直向上。
  2. 取到BeanDefinition后,获取当前Bean所依赖的所有Bean,并递归调用getBean
  3. 通过createBean创建Bean的实例,最后返回Bean
  4. createBean()中,调用createBeanInstance()创建Bean(默认使用CGLIB一个常用的字节码生成器类库、或使用JVM的反射)
  5. createBean()中,再调用populateBean()方法,将当前Bean的依赖注入,通过递归调用容器的getBean方法,得到当前Bean的依赖Bean,同时也触发对依赖Bean的创建和注入。

2由BeanWrapper对构造完成的bean实例进行包裹,返回相应的BeanWrapper实例。并对bean实例进行进一步处理,比如设置或者获取bean的相应属性值

3、检查当前bean实例是否java代码中实现了一系列的以Aware命名结尾的接口定义,如果是,则该bean实例可以获得相应接口中的方法

4、检查容器中是否有BeanPostProcessor实现类,如果有,则在其两个分别在init-method执行前和执行后执行的方法中对实例化的bean对象进行处理SpringAOP就是使用BeanPostProcessor来为对象生成相应的代理对象

5在对象实例化过程调用过“BeanPostProcessor前置处理”之后,会接着检测当前对象是否实现了InitializingBean接口和xmlbean是否有init-method,如果有则会进一步调用对应方法调整对象实例的状态。

6BeanPostProcessor后置处理“之后,检查是否有destroy-method属性,如果是,就会为该实例注册一个用于对象销毁的回调( Callback),以便在这些singleton类型的对象实例销毁之前异步地执行销毁逻辑。为对象提供了执行自定义销毁逻辑的机会。

销毁逻辑不适用于prototype的对象

7、实例化阶段结束,返回给调用者。

Spring 针对 Bean 管理中创建对象提供注解

(1) @Component

(2) @Service

(3) @Controller

(4) @Repository

基于注解方式实现属性注入

(1) @Autowired:根据属性类型进行自动装配

2) @Qualifier:根据名称进行注入

3) @Resource:可以根据类型注入,可以根据名称注入

(4) @Value:注入普通类型属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值