Spring Bean管理--IOC容器简介

一、摘要

本文主要介绍Spring Bean管理的IOC容器部分:BeanFactory和ApplicationContext,以及Bean如何创建、销毁,如何通过InitializingBean、BeanPostProcessor等接口或init-method、destroy-method等bean自身方法进行生命周期管理。

二、IOC容器

简单理解,BeanFactory和ApplicationContext是Spring IOC两大容器。其中BeanFactory作为最顶层的一个接口类,亦是IOC容器的核心接口,它定义了IOC容器的基本功能规范,DefaultListableBeanFactory是其默认实现类,最常用一个方法就是getBean。ApplicationContext接口扩展了BeanFactory,还提供了AOP、国际化处理、事件传播及不同层次的context实现 (如针对web应用的WebApplicationContext)。

1、先看看两者的简单使用方法
1)xml配置文件 helloWorldBean.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"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="helloWorld" class="com.marcus.spring.beans.HelloWorldBean">
       <property name="message" value="Hello World!"/>
   </bean>
</beans>
2)Java代码
package com.marcus.spring.beans;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/**
 * BeanApp.
 */
public class BeanApp {
    public static void main(String[] args) {
        // beanfactory
        beanFactory();

        //
        applicationContext();
    }

    private static void beanFactory() {
        Resource resource=new ClassPathResource("helloWorldBean.xml");  
        BeanFactory fa=new DefaultListableBeanFactory();  
        BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) fa);  
        bdr.loadBeanDefinitions(resource);
        //
        System.out.println("get bean by beanFactory.");
        HelloWorldBean helloWorld = fa.getBean("helloWorld", HelloWorldBean.class);
        helloWorld.getMessage();
        System.out.println(helloWorld);
        helloWorld.setMessage("tmd singleton!");

        //验证是否单例
        helloWorld = fa.getBean("helloWorld", HelloWorldBean.class);
        helloWorld.getMessage();
        System.out.println(helloWorld);
    }

    private static void applicationContext() {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("helloWorldBean.xml");

        System.out.println("=================================================");
        System.out.println("get bean by applicationContext.");
        HelloWorldBean helloWorld = context.getBean("helloWorld", HelloWorldBean.class);
        helloWorld.getMessage();
        System.out.println(helloWorld);
        helloWorld.setMessage("tmd singleton!");

        //验证是否单例
        helloWorld = context.getBean("helloWorld", HelloWorldBean.class);
        helloWorld.getMessage();
        System.out.println(helloWorld);

        context.close();
    }
}
3) 控制台输出
get bean by beanFactory.
Your Message : Hello World!
com.marcus.spring.beans.HelloWorldBean@64616ca2
Your Message : tmd singleton!
com.marcus.spring.beans.HelloWorldBean@64616ca2
=================================================
get bean by applicationContext.
Your Message : Hello World!
com.marcus.spring.beans.HelloWorldBean@5bcab519
Your Message : tmd singleton!
com.marcus.spring.beans.HelloWorldBean@5bcab519
2、两者区别
1)两者Bean加载方式不同

BeanFactroy采用的是延迟加载形式来注入Bean的,读取配置文件加载的是Bean定义,只有在使用某个Bean时(调用getBean()),才对该Bean进行加载实例化。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有Bean。相对于基本的BeanFactory,ApplicationContext唯一的不足是耗内存,当应用程序配置Bean较多时,程序启动较慢。

2)自动化程度不一样

BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但BeanFactory需要手动注册,而ApplicationContext则是自动注册。比如BeanPostProcessor,ApplicationContext在xml文件中配置即可,而BeanFactory则需手动编写代码。假设:TestBeanPostProcessor是BeanPostProcessor的实现类,那么:

  • ApplicationContext:
    只要在xml中配置 bean class=”TestBeanPostProcessor”,
  • BeanFactory则需要手动编写代码:
    factory.addBeanPostProcessor(new TestBeanPostProcessor());
3)功能丰富程度不一样

ApplicationContext扩展了BeanFactory,较BeanFactory有更多功能:

  • 国际化(MessageSource)
  • 访问资源,如URL和文件(ResourceLoader)
  • 载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定的层次,比如WebApplicationContext
  • 事件传播,自定义事件(ApplicationEventPublisher)
  • AOP(拦截器)
3、两者使用场景

BeanFactory主要面对spring框架的基础设施,面对spring自身。而ApplicationContext 主要面对spring开发者,本文后续部分都使用ApplicationContext管理Bean。

三、Bean生命周期

理解Spring bean的生命周期很容易,实例化–>初始化–>销毁。当一个bean被实例化时,它可能需要执行一些初始化使它转换成可用状态;同样,当bean不再需要,从容器中移除时,可能需要做一些清理工作。

1、跟生命周期相关的方法、接口说明
1)Bean自身方法——配置文件

init-method/destroy-method,通过配置文件bean定义中添加相应属性指定相应执行方法,或默认的全局初始化或销毁方法:default-init-method=”init”等。

bean init/destroy方法
<bean id=”xxx” class=”xxx” init-method=”init” destroy-method=”destroy” />
=============================
默认的初始化或销毁方法
<beans …
default-init-method=”init” default-destroy-method=”destroy”>

2)Bean自身方法——注解

@PostConstruct,@PreDestroy

3)Bean级生命周期接口
  • InitializingBean: void afterPropertiesSet() throws Exception;
  • DiposableBean: void destroy() throws Exception;
  • BeanNameAware: void setBeanName(String name);
  • BeanFactoryAware: void setBeanFactory(BeanFactory beanFactory);
4)容器级生命周期接口方法

包括InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现(前者继承自后者),即所谓的后置处理器。

5)工厂后处理器接口方法

这些方法也是容器级别的,例如BeanFactoryPostProcessor、 CustomAutowireConfigurer等。

2、Bean生命周期相关代码实例
1)xml配置文件 beanLifeCycle.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"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

   <bean id="helloWorld" class="com.marcus.spring.beans.HelloWorldLifeCycle" 
        init-method="beanInit" destroy-method="beanDestroy" >
       <property name="message" value="Hello World!"/>
   </bean>

   <bean id="beanPostProcessorTest" class="com.marcus.spring.beans.BeanPostProcessorTest" />
</beans>

注意:因为bean使用了@PostConstruct,所以配置文件添加了context:annotation-config

2)java bean 代码
package com.marcus.spring.beans;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

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;

/**
 * HelloWorld生命周期Bean.
 * @author marcus
 *
 */
public class HelloWorldLifeCycle implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean {
    private String message;

    public void setMessage(String message) {
        this.message = message;
    }

    public void getMessage() {
        System.out.println("bean getMessage(), message = " + message);
    }

    // DisposableBean
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean->destroy() executed!");
    }

    // InitializingBean
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean->afterPropertiesSet() executed!");
    }

    // BeanFactoryAware
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware->setBeanFactory(), 此时factory = " + beanFactory);
    }

    // BeanNameAware
    @Override
    public void setBeanName(String name) {
        System.out.println("BeanNameAware->setBeanName(), 此时name = " + name);
    }

    public void beanInit() {
        System.out.println("bean init-method: beanInit() executed.");
    }

    public void beanDestroy() {
        System.out.println("bean destroy-method: beanDestroy() executed.");
    }

    @PostConstruct
    public void beanPostInit() {
        System.out.println("Bean @PostConstruct beanPostInit executed.");
    }

    @PreDestroy
    public void beanPreDestroy() {
        System.out.println("Bean @PreDestroy beanPreDestroy executed.");
    }   
}
3) 测试类 java 代码
public static void main(String[] args) {
    beanLifeCycle();
}

private static void beanLifeCycle() {
    AbstractApplicationContext context = new ClassPathXmlApplicationContext("beanLifeCycle.xml");

    HelloWorldLifeCycle helloWorld = context.getBean("helloWorld", HelloWorldLifeCycle.class);
    helloWorld.getMessage();
    System.out.println("bean ID: " + helloWorld);
    context.close();
}

注意:为了触发@PreDestroy或destroy-method或DisposableBean,使用了AbstractApplicationContext,并close()。

4) 控制台输出
BeanNameAware->setBeanName(), 此时name = helloWorld
BeanFactoryAware->setBeanFactory(), 此时factory = org.springframework.beans.factory.support.DefaultListableBeanFactory@366e2eef: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,helloWorld,beanPostProcessorTest,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
BeanPostProcessor->postProcessBeforeInitialization : helloWorld
Bean @PostConstruct beanPostInit executed.
InitializingBean->afterPropertiesSet() executed!
bean init-method: beanInit() executed.
BeanPostProcessor->postProcessAfterInitialization : helloWorld
bean getMessage(), message = Hello World!
bean ID: com.marcus.spring.beans.HelloWorldLifeCycle@1b68ddbd
Bean @PreDestroy beanPreDestroy executed.
DisposableBean->destroy() executed!
bean destroy-method: beanDestroy() executed.
3、Bean生命周期总结
1)常用使用方式
  • 通过xml配置实现的bean自身的init、destroy方法;
  • 通过java代码注解实现的@PostConstruct,@PreDestroy方法;
  • BeanPostProcessor
2)@PostConstruct InitializingBean init-method执行顺序问题

通过上述代码我们可以推断出,3者执行顺序为:@PostConstruct > InitializingBean > init-method,原因:

1) BeanPostProcessor的postProcessBeforeInitialization是在afterPropertiesSet和init-method之前执被调用;
2) @PostConstruct背后实现原理是CommonAnnotationBeanPostProcessor,本质上就是BeanPostProcessor,所以@PostConstruct在其它2个方法前执行;
3)至于InitializingBean,init-method则是bean构建完后,spring先会判断bean是否实现InitializingBean,如果有则调用afterPropertiesSet方法,然后判断是否指定了init-method,如果有则通过反射调用指定方法。

猜你喜欢

转载自blog.csdn.net/chuangxin/article/details/81193862