《Spring》(八)---- IoC容器及Bean的生命周期

本文内容纲要:《Spring》(八)---- IoC容器及Bean的生命周期

  Spring的IoC容器会以某种方式加载配置信息,然后根据这些信息绑定整个系统的对象,最终组装成一个可用的基于轻量级容器的应用系统。实现以上功能,分为两个阶段:容器启动阶段和Bean实例化阶段。而且Spring的IoC容器在每个阶段都加入了相应的扩展点,以便根据具体场景的需要加入自定义的扩展逻辑。

 ** 1 容器启动阶段**

**  **首先会通过某种途径加载配置信息,大部分情况下,容器需要依赖某些工具类(BeanDefinitionReader)对加载的配置信息进行解析和分析,并将分析后的信息编组为相应的BeanDefinition,最后把这些保存了bean定义必要信息的BeanDefinition,注册到相应的BeanDifinitionRegistry,这样容器启动工作就完成了。

  该阶段所作工作是准备性的,重点更加侧重于对象管理信息的收集,以及一些验证性的和辅助性的工作。

  2 Bean实例化阶段

**  **现在所有的bean定义信息都已经注册到了BeanDefinitionRegistry中,当某个请求方通过容器的getBean方法明确地请求某个对象,或者因依赖关系容器需要隐式地调用getBean方法时,就会触发bean实例化。

  在这一阶段,容器会先检查所请求的对象之前是否已经初始化,如果没有,会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。如果该对象实现了某些回调接口,也会根据回调接口的要求来装配它。当该对象装配完毕之后,容器会立即将其返回请求方使用。

  3 干预容器启器

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

  可以通过两种方式来应用BeanFactoryPostProcessor, 分别针对基本的IoC容器BeanFactory和较为先进的容器ApplicationContext.

  对于BeanFactory来说,我们需要用手动方式应用所有的BeanFactoryPostProcessor:

ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("..."));

PropertyPlaceholderConfigurer propertyPostProcessor = new PropertyPlaceholderConfigurer();

propertyPostProcessor.setLocation(new ClassPathResource("..."));

propertyPostProcessor.postProcessBeanFactory(beanFactory);

  对于ApplicationContext来说,它会自动识别配置文件中的BeanFactoryPostProcessor并应用它,所以仅需要在XML中将这些BeanFacotryPostProcessor简单配置一下即可。

<beans>

<bean    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

    <property name="locations">

       <list>

        <value>conf/jdbc.properties</value>

        <value>conf/mail.properties</value> </list>

    </property>

</bean>

...

</beans>

Spring提供的几个BeanFactoryPostProcessor

  • PropertyPlaceholderConfigurer

  PropertyPlaceholderConfigurer允许在XML配置文件中使用占位符,并将这些占位符所代表的资源单独配置到简单的properties文件中来加载。以数据源的配置为例:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="url">

  <value>${jdbc.url}</value>

  </property>

  <property name="driverClassName">

    <value>${jdbc.driver}</value>

  </property>

  <property name="username">

    <value>${jdbc.username}</value>

  </property>

  <property name="password">

    <value>${jdbc.password}</value>

  </property>

   

    100

   

< /bean> 

jdbc.properties文件如下: 

jdbc.url=jdbc:mysql://server/MAIN?useUnicode=true&characterEncoding=ms932& 

failOverReadOnly=false&roundRobinLoadBalance=true

jdbc.driver=com.mysql.jdbc.Driver

jdbc.username=your username

jdbc.password=your password

原理:

  当BeanFactory在第一阶段加载完成所有配置信息时,BeanFactory中保存的对象的属性信息还只是以占位符的形式存在,如${jdbc.url}。当PropertyPlaceholderConfigurer作为BeanFactoryPostProcessor被应用时,它会使用properties配置文件中的配置信息来替换相应BeanDefinition中占位符表示的属性值。这样,当进入容器实现的第二个阶段实例化bean时,bean定义中的属性值就是最终替换完成后的了。

  PropertyPlaceholderConfigurer不仅会从其配置的properties文件中加载配置项,同时还会检查System类中的Properties. PropertyPlaceholderConfigurer提供了SYSTEM_PROPERTIES_MODE_FALLBACK/SYSTEM_PROPERTIES_MODE_NEVER/SYSTEM_PROPERTIES_MODE_OVERRIDE三种模式,默认采用FALLBACK,即如果properties文件中找不到相应配置项,则到System的properties中查找。

  • PropertyOverrideConfigurer

**  **PropertyOverrideConfigurer可以对容器中配置的任何你想处理的bean定义的property信息进行覆盖替换。比如前一个例子中的dataSource,maxActive值为100, 如果想把这个值覆盖掉,改成200,就可以在一个properties文件中配置:

dataSource.maxActive=200

  所以如果要对容器中某些bean的property信息进行覆盖,需要按照如下规则提供一个PropertyOverrideConfigurer使用的配置文件:

beanName.propertyName=value

也就是说,properties文件中的键是以XML中配置的bean定义的beanName为标志开始的(通常就是id指定的值),后面跟着相应被覆盖的property的名称。如下是PropertyOverridConfigurer在XML中的配置信息:

<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">

  <property name="location" value="pool-adjustment.properties"/>

</bean>

当容器中配置的多个PropertyOverrideConfigurer对同一个bean定义的同一个property值进行处理的时候,最后一个会生效。

  4 Bean的生命周期

转载自 http://www.jianshu.com/p/3944792a5fff

  • ApplicationContext Bean生命周期

  1. Bean的实例化

  首先容器启动后,会对scope为singleton且非懒加载的bean进行实例化。

  容器在内部实现的时候,采用“策略模式”来决定采用何种方式初始化bean实例。通常,可以通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或者动态生成其子类。默认情况下,容器内部采用CglibSubclassingInstantiationStartegy。容器只要根据相应bean定义的BeanDefinition取得实例化信息,结合CglibSubclassingInstantiationStartegy以及不同的bean定义类型,就可以返回实例化完成的对象实例。但不是直接返回构造完成的对象实例,而是以BeanWrapper对构造完成的对象实例进行包裹,返回相应的BeanWrapper实例。这个BeanWrapper的实现类BeanWrapperImpl是对某个bean进行包裹,然后对包裹后的bean进行操作,比如设置或获取bean的相应属性值。

  1. 设置对象属性

  BeanWrapper继承了PropertyAccessor接口,可以以同一的方式对对象属性进行访问,同时又继承了PropertyEditorRegistry和TypeConverter接口,然后BeanWrapper就可以很方便地对bean注入属性了。

  1. 如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该bean的id,此时该Bean就获得了自己在配置文件中的id。

  2. 如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory.

  3. 如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入该Bean的ApplicationContext, 这样该Bean就获得了自己所在的ApplicationContext.

  4. 如果有一个Bean实现了BeanPostProcessor接口,并将该接口配置到配置文件中,则会调用该接口的postProcessBeforeInitialization()方法。

7.如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法。

  1. 如果Bean配置了init-method方法,则会执行init-method配置的方法。

  2. 如果有一个Bean实现了BeanPostProcessor接口,并将该接口配置到配置文件中,则会调用该接口的postProcessAfterInitialization方法。

10.经过9之后,就可以正式使用该Bean了,对于scope为singleton的Bean, Spring IoC容器会缓存一份该Bean的实例,而对于scope为prototype的Bean, 每次被调用都回new一个对象,而且生命周期也交给调用方管理了,不再是Spring容器进行管理了。

  1. 容器关闭后,如果Bean实现了DisposableBean接口,则会调用该接口的destroy()方法。

  2. 如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法,至此,整个Bean生命周期结束。

示例

我们定义了一个Person类,该类实现了BeanNameAware,BeanFactoryAware,ApplicationContextAware,InitializingBean,DisposableBean五个接口,并且在applicationContext.xml文件中配置了该Bean的id为person1,并且配置了init-method和destroy-method,为该Bean配置了属性name为jack的值,然后定义了一个MyBeanPostProcessor方法,该方法实现了BeanPostProcessor接口,且在applicationContext.xml文件中配置了该方法的Bean

Person.class

package com.ivy.beanlifecycle;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.BeanFactoryAware;

import org.springframework.beans.factory.BeanNameAware;

import org.springframework.beans.factory.DisposableBean;

import org.springframework.beans.factory.InitializingBean;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean{

private String name;

public Person() {

System.out.println("Person constructor");

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

System.out.println("setter() invoked");

}

public void myInit() {

System.out.println("myInit() invoked");

}

public void myDestroy() {

System.out.println("myDestroy() invoked");

}

@Override

public void setBeanName(String beanName) {

System.out.println("setBeanName() invoked, beanName : " + beanName);

}

@Override

public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

// TODO Auto-generated method stub

System.out.println("setBeanFactory() invoked, beanFactory : " + beanFactory);

}

@Override

public void setApplicationContext(ApplicationContext applicationContext)

throws BeansException {

System.out.println("setApplicationContext() invoked");

}

@Override

public void afterPropertiesSet() throws Exception {

System.out.println("afterPropertiesSet() invoked");

}

@Override

public void destroy() throws Exception {

System.out.println("destroy() invoked");

}

public String toString() {

return "Person[name=" + name +"]";

}

}

MyBeanPostProcessor.class

package com.ivy.beanlifecycle;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor{

@Override

public Object postProcessAfterInitialization(Object bean, String beanName)

throws BeansException {

// TODO Auto-generated method stub

System.out.println("postProcessAfterInitialization() invoked, beanName : " + beanName);

return bean;

}

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName)

throws BeansException {

System.out.println("postProcessBeforeInitialization() invoked, beanName : " + beanName);

return bean;

}

}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="person1" class="com.ivy.beanlifecycle.Person" init-method="myInit" destroy-method="myDestroy">

<property name="name" value="ivy"></property>

</bean>

<bean id="myPostProcessor" class="com.ivy.beanlifecycle.MyBeanPostProcessor"></bean>

</beans>

PersonServiceApplicationContextTest.class

package com.ivy.beanlifecycle;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PersonServiceApplicationContextTest{

public static void main(String[] args) {

// TODO Auto-generated method stub

System.out.println("start init ioc container");

ApplicationContext aContext = new ClassPathXmlApplicationContext("applicationContext.xml");

System.out.println("end loading xml");

Person person = (Person)aContext.getBean("person1");

System.out.println(person);

System.out.println("close container");

((ClassPathXmlApplicationContext)aContext).close();

}

}

运行结果:

start init ioc container

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).

log4j:WARN Please initialize the log4j system properly.

Person constructor

setter() invoked

setBeanName() invoked, beanName : person1

setBeanFactory() invoked, beanFactory : org.springframework.beans.factory.support.DefaultListableBeanFactory@5fa12d: defining beans [person1,myPostProcessor]; root of factory hierarchy

setApplicationContext() invoked

postProcessBeforeInitialization() invoked, beanName : person1

afterPropertiesSet() invoked

myInit() invoked

postProcessAfterInitialization() invoked, beanName : person1

end loading xml

Person[name=ivy]

close container

destroy() invoked

myDestroy() invoked

  可以看出,在加载xml的时候ApplicationContext就实例化了所有的bean

  • BeanFactory Bean生命周期

BeanFactoty容器中, Bean的生命周期如上图所示,与ApplicationContext相比,有如下几点不同:

  1. BeanFactory容器中,不会调用ApplicationContextAware接口的setApplicationContext()方法

  2. BeanPostProcessor接口的postProcessBeforeInitialization方法和postProcessAfterInitialization方法不会自动调用,必须自己通过代码手动注册

  3. BeanFactory容器启动的时候,不会去实例化所有bean,包括所有scope为singleton且非延迟加载的bean也是一样,而是在调用的时候去实例化。

还是以上边Person为示例

PersonServiceBeanFactoryTest.class

package com.ivy.beanlifecycle;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import org.springframework.beans.factory.xml.XmlBeanFactory;

import org.springframework.core.io.ClassPathResource;

public class PersonServiceBeanFactoryTest {

public static void main(String[] args) {

// TODO Auto-generated method stub

System.out.println("start init ioc container");

ConfigurableListableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

System.out.println("end loading xml");

beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());

Person person = (Person)beanFactory.getBean("person1");

System.out.println(person);

System.out.println("close container");

beanFactory.destroySingletons();

}

}

运行结果:

start init ioc container

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).

log4j:WARN Please initialize the log4j system properly.

end loading xml

Person constructor

setter() invoked

setBeanName() invoked, beanName : person1

setBeanFactory() invoked, beanFactory : org.springframework.beans.factory.xml.XmlBeanFactory@ccd65d: defining beans [person1,myPostProcessor]; root of factory hierarchy

postProcessBeforeInitialization() invoked, beanName : person1

afterPropertiesSet() invoked

myInit() invoked

postProcessAfterInitialization() invoked, beanName : person1

Person[name=ivy]

close container

destroy() invoked

  可以看出,end loading xml之后才实例化的person。

本文内容总结:《Spring》(八)---- IoC容器及Bean的生命周期

原文链接:https://www.cnblogs.com/IvySue/p/6484599.html

以上是 《Spring》(八)---- IoC容器及Bean的生命周期 的全部内容, 来源链接: utcz.com/z/362442.html

回到顶部