spring创建对象的生命周期

spring作为一个IOC容器,主要作用是进行对象的创建和在容器中进行对象的管理,spring创建对象的时候,主要试用了工厂设计模式,并且对象创建过程是会经过一系列的处理。在spring创建对象和销毁的过程中,主要涉及的spring中的接口有:

  1. InitializingBean
  2. DisposableBean
  3. BeanPostProcessor bean后置处理器
    另外,在spring创建对象后,会涉及对象中属性值的注入,注入过程中会涉及类型的转换,主要涉及的接口为:
  4. Converter

我们来看一下前三个接口的作用以及整个spring创建对象的过程:

  • InitializingBean接口:此接口作用是在对象属性注入完成后,调用其afterPropertiesSet方法,实现一些相关的初始化工作
  • DisposableBean接口:此接口作用是在IOC容器销毁时进行调用,完成一些善后的工作
  • BeanPostProcessor接口,此接口中有两个方法:postProcessBeforeInitialization和postProcessAfterInitialization,其中第一个方法时在对象初始化之前进行调用,第二个方法在对象初始化完成后进行调用

我们试用代码来看一下整体的创建和初始化过程:

@Data
public class Person implements InitializingBean, DisposableBean {

    private String name ;

    private Date birth ;


    public void setName(String name){
        this.name = name ;
        System.out.println("Person.setName");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Person.destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Person.afterPropertiesSet");
    }
}
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization: " + bean.getClass().getName());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor.postProcessAfterInitialization: " + bean.getClass().getName());
        return bean;
    }
}
<!-- Person对象的声明 -->
<bean id="person" class="com.huwc.bean.Person">
        <property name="name" value="huwenchao"></property>
        <property name="birth" value="1986/06/26"></property>
</bean>

<!-- bean后置处理器的注册-->
<bean class="com.huwc.processor.MyBeanPostProcessor"></bean>

测试代码:

@Test
    public void test1(){
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
        Person p = (Person) ctx.getBean("person");
        System.out.println("p = " + p);
        ctx.close();

    }

打印结果:

Person.setName
MyBeanPostProcessor.postProcessBeforeInitialization: com.huwc.bean.Person
Person.afterPropertiesSet
MyBeanPostProcessor.postProcessAfterInitialization: com.huwc.bean.Person
p = Person(name=huwenchao, birth=Thu Jun 26 00:00:00 CDT 1986)
Person.destroy

从以上的打印结果中我们可以看到整体的对象创建过程,如下:

  1. 调用person对象的set方法,进行属性值的注入
  2. 调用bean后置处理器的postProcessBeforeInitialization方法,进行对象初始化之前的拦截
  3. 调用InitializingBean接口的afterPropertiesSet方法,进行对象的初始化工作
  4. 调用bean后置处理器的postProcessAfterInitialization方法,进行对象初始化之后的拦截
  5. 调用DisposableBean的destroy,进行善后处理工作

以上,就是spring中创建对象并初始化的一系列过程。

Converter接口,主要时在对象进行属性值的注入时,进行类型的转换处理,我们也来看一下这个接口的作用:
对象在进行属性值的注入时,我们以Date类型来进行举例,在上面的代码执行中,我们可以看到:Person中有一个birth属性,是Date类型,并且我们没有配置相应的Converter,然而属性值却正常注入了,这是因为Spring中有一个默认的Date类型转换器,其实现了和String的“yyyy/mm/dd" 的转换,如果我们不想采用这种日期格式,那么就需要我们自己来实现相应的Converter了:
代码:

@Data
public class MyDateConverter implements Converter<String, Date> {

    private String pattern ;

    public Date convert(String source) {

        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        Date ret = null ;
        try {
            ret = sdf.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return ret;
    }
}
<bean id="myDateConverter" class="MyDateConverter">
        <property name="pattern" value="yyyy-mm-dd"></property>
    </bean>

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
     <property name="converters">
         <set>
             <ref bean="myDateConverter"></ref>
         </set>
     </property>
 </bean>
 
 <bean id="person" class="com.huwc.bean.Person">
        <property name="name" value="huwenchao"></property>
        <property name="birth" value="1986-06-26"></property>
    </bean>

测试结果:

p = Person(name=huwenchao, birth=Sun Jan 26 00:06:00 CST 1986)

以上,可以看到,我们在属性设置中,采用了”yyyy-mm-dd"的格式,并且通过自定义的Converter实现了类型的转换,成功进行了注入。
注意:在xml中注册converterService的时候,bean的id,必须指定为“conversionService”,如果设置为别的名称,则会报错。