Spring中单个bean的加载步骤

Spring框架中对于单个bean生成其实例时,需要经过一系列步骤。

其每个步骤一般都是实现某个接口,或者配置指定某个方法(如指定init方法)来达到目的。

可以编写一个bean,实现所有要测试的接口,配置指定的方法,来观察其执行顺序。

 

网上查阅相关资料,相关文章转发如下:

以下内容转自:http://blog.csdn.net/hsgao_water/article/details/52402264

Spring-Bean初始化顺序

在验证spring-Bean初始化顺序前,先看几个关键接口

InitializingBean
    Spirng的InitializingBean为bean提供了定义初始化方法的方式。InitializingBean是一个接口,它仅仅包含一个方法:afterPropertiesSet()。
   在spring 初始化后,执行完所有属性设置方法(即setXxx)将自动调用 afterPropertiesSet(), 在配置文件中无须特别的配置, 但此方式增加了bean对spring 的依赖,应该尽量避免使用

init-method(非接口)
  Spring虽然可以通过InitializingBean完成一个bean初始化后对这个bean的回调,但是这种方式要求bean实现 InitializingBean接口。一但bean实现了InitializingBean接口,那么这个bean的代码就和Spring耦合到一起了。通常情况下我不鼓励bean直接实现InitializingBean,可以使用Spring提供的init-method的功能来执行一个bean 子定义的初始化方法。

BeanFactoryPostProcessor接口


可以在spring的bean创建之前,修改bean的定义属性。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置'order'属性来控制各个BeanFactoryPostProcessor的执行次序。
注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息

BeanPostProcessor接口

BeanPostProcessor,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。这里说的初始化方法,指的是下面两种:
1)bean实现了InitializingBean接口,对应的方法为afterPropertiesSet
2)在bean定义的时候,通过init-method设置的方法

注意:BeanPostProcessor是在spring容器加载了bean的定义文件并且实例化bean之后执行的。BeanPostProcessor的执行顺序是在BeanFactoryPostProcessor之后。

代码:

 

[java] view plain copy
 
  1. <span style="font-size:14px;">package cn.com.init;  
  2.   
  3. import org.springframework.beans.BeansException;  
  4. import org.springframework.beans.factory.BeanFactory;  
  5. import org.springframework.beans.factory.BeanFactoryAware;  
  6. import org.springframework.beans.factory.BeanNameAware;  
  7. import org.springframework.beans.factory.DisposableBean;  
  8. import org.springframework.beans.factory.InitializingBean;  
  9. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;  
  10. import org.springframework.beans.factory.config.BeanPostProcessor;  
  11. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;  
  12.   
  13. public class HelloWorld implements InitializingBean, BeanPostProcessor, BeanFactoryPostProcessor, BeanFactoryAware,  
  14.         BeanNameAware, DisposableBean {  
  15.   
  16.     public HelloWorld() {  
  17.         System.out.println("调用HelloWorld构造器...");  
  18.     }  
  19.   
  20.     private String hello;  
  21.   
  22.     public String getHello() {  
  23.         return hello;  
  24.     }  
  25.   
  26.     public void setHello(String hello) {  
  27.         this.hello = hello;  
  28.         System.out.println("调用setHello()...");  
  29.     }  
  30.   
  31.     @Override  
  32.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
  33.         System.out.println("调用BeanPostProcessor的postProcessBeforeInitialization()...");  
  34.         return bean;  
  35.     }  
  36.   
  37.     @Override  
  38.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
  39.         System.out.println("调用BeanPostProcessor的postProcessAfterInitialization()...");  
  40.         return bean;  
  41.     }  
  42.   
  43.     @Override  
  44.     public void afterPropertiesSet() throws Exception {  
  45.         System.out.println("调用InitializingBean的afterPropertiesSet()...");  
  46.     }  
  47.   
  48.     @Override  
  49.     public void postProcessBeanFactory(ConfigurableListableBeanFactory paramConfigurableListableBeanFactory)  
  50.             throws BeansException {  
  51.         System.out.println("调用BeanFactoryPostProcessor的postProcessBeanFactory()...");  
  52.   
  53.     }  
  54.   
  55.     @Override  
  56.     public String toString() {  
  57.         return "HelloWorld [hello=" + hello + "]";  
  58.     }  
  59.   
  60.     @Override  
  61.     public void setBeanName(String paramString) {  
  62.         System.out.println("调用BeanNameAware.setBeanName");  
  63.   
  64.     }  
  65.   
  66.     @Override  
  67.     public void setBeanFactory(BeanFactory paramBeanFactory) throws BeansException {  
  68.         System.out.println("调用BeanFactoryAware.setBeanFactory");  
  69.   
  70.     }  
  71.   
  72.     @Override  
  73.     public void destroy() throws Exception {  
  74.         System.out.println("DisposableBean 接口 destroy方法");  
  75.   
  76.     }  
  77.   
  78.     public void init() throws Exception {  
  79.         System.out.println("HelloWorld类init 方法");  
  80.   
  81.     }  
  82. }  
  83. </span>  


配置文件:

 

 

[java] view plain copy
 
  1. <span style="font-size:14px;"><?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
  4.     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
  5.     xmlns:context="http://www.springframework.org/schema/context"  
  6.     xmlns:aop="http://www.springframework.org/schema/aop"  
  7.     xsi:schemaLocation="  
  8.             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
  9.             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd   
  10.             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
  11.             http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
  12.             http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"  
  13.     default-lazy-init="false">  
  14.   
  15.     <!--  <bean id="myJavaBean" class=" cn.com.init.MyJavaBean" init-method="initMethod">  
  16.         <property name="desc" value="原始的描述信息" />  
  17.         <property name="remark" value="原始的备注信息" />  
  18.     </bean>  
  19.   
  20.     <bean id="myBeanPostProcessor" class=" cn.com.init.MyBeanPostProcessor" />  
  21.     <bean id="myBeanFactoryPostProcessor" class=" cn.com.init.MyBeanFactoryPostProcessor" />  -->  
  22.   
  23. <bean id="hello" class="cn.com.init.HelloWorld" init-method="init" >  
  24. <property name="hello" value="hello" />  
  25. </bean>  
  26. </beans></span>  


测试方法:

 

 

[java] view plain copy
 
  1. <span style="font-size:14px;">package mybatis;  
  2.   
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  4.   
  5. import cn.com.init.HelloWorld;  
  6. import junit.framework.TestCase;  
  7.   
  8. public class BeanPostPorcessorTest extends TestCase {  
  9.     private ClassPathXmlApplicationContext context;    
  10.     protected void setUp() throws Exception {    
  11.         super.setUp();    
  12.         String[] paths = {"classpath*:spring-text.xml"};    
  13.     
  14.         context = new ClassPathXmlApplicationContext(paths);    
  15.             
  16.     }    
  17.         public void testBeanFactoryPostProcessor()    
  18.         {    
  19.              HelloWorld bean = (HelloWorld) context.getBean("hello");    
  20.              System.out.println(bean);  
  21.              context.getBeanFactory().destroySingletons();  
  22.   
  23.         }    
  24. }  
  25. </span>  


执行结果:

 

调用HelloWorld构造器...
调用setHello()...
调用BeanNameAware.setBeanName
调用BeanFactoryAware.setBeanFactory
调用InitializingBean的afterPropertiesSet()...
HelloWorld类init 方法
调用BeanFactoryPostProcessor的postProcessBeanFactory()...
HelloWorld [hello=hello]

DisposableBean 接口 destroy方法

由结果得出初始化bean顺序

1.构造函数
2.初始化属性
3.如果实现了BeanFactoryAware 接口执行setBeanFactory方法
4..如果实现了InitializingBean 接口执行afterPropertiesSet方法
5.如果在配置文件中指定了init-method,那么执行该方法
6..如果实现了BeanFactoryPostProcessor 接口在 “new”其他类之前执行 postProcessBeanFactory 方法(通过这个方法可以改变配置文件里面的属性值的配置)
7.如果实现了BeanPostProcessor 接口,那么会在其他bean初始化方法之前执行postProcessBeforeInitialization 方法,之后执行postProcessAfterInitialization方法
感觉奇怪的地方就是没有执行destroy方法
在此方法中没有执行接口BeanPostProcessor的方法,不知道何原因

 

以下内容转自:http://wolfdream.iteye.com/blog/1172821

spring加载Bean顺序【转】

一,单一Bean

  • 装载

1. 实例化; 
2. 设置属性值; 
3. 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name; 
4. 如果实现BeanFactoryAware接口,调用setBeanFactory 设置BeanFactory; 
5. 如果实现ApplicationContextAware,调用setApplicationContext设置ApplicationContext 
6. 调用BeanPostProcessor的预先初始化方法; 
7. 调用InitializingBean的afterPropertiesSet()方法; 
8. 调用定制init-method方法; 
9. 调用BeanPostProcessor的后初始化方法;

  • spring容器关闭

1. 调用DisposableBean的destroy(); 
2. 调用定制的destroy-method方法;

 

问题来源:

有一个bean为A,一个bean为B。想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值。

如果只是在A里单纯的写着:

private B b;
private String name = b.funb();

会报错说nullpointException,因为这个时候b还没被set进来,所以为null。

解决办法为如下代码,同时学习下spring中  InitializingBean   ,对象构造方法   ,  init-method   的执行顺序。

 

Java代码   收藏代码
  1. public class A implements InitializingBean {  
  2.   
  3.  private B b;  
  4.  private String name; // = b.funb();  
  5.   
  6.  public void setB(B b) {  
  7.   System.out.println("A.setB initialed");  
  8.   this.b = b;  
  9.  }  
  10.   
  11.  public A() {  
  12.   System.out.println("A initialed");  
  13.  }  
  14.   
  15.  public void init() {  
  16.   System.out.println("init");  
  17.   this.name = b.funb();  
  18.  }  
  19.   
  20.  @Override  
  21.  public String toString() {  
  22.   return super.toString() + this.name;  
  23.  }  
  24.   
  25.  public void afterPropertiesSet() throws Exception {  
  26.   
  27.   //其实放在这里也可以  
  28.   
  29.   //this.name = b.funb();  
  30.   System.out.println("afterPropertiesSet");  
  31.   
  32.  }  
  33.   
  34. }  
  35.   
  36. public class B {  
  37.   
  38.  public String funb() {  
  39.   System.out.println("funb");  
  40.   return "B.funb";  
  41.  }  
  42.   
  43.  public B() {  
  44.   System.out.println("B initialed");  
  45.  }  
  46. }  

 

 

spring配置文件

<beans default-autowire="byName">
      <bean id="a" class="testspring.A" init-method="init">
      </bean>
      <bean id="b" class="testspring.B">
      </bean>
 </beans>

 

测试代码:

 public static void main(String[] args) {
      ApplicationContext context = new FileSystemXmlApplicationContext(
          "src/testspring/bean.xml");
       A a = (A) context.getBean("a");
      System.out.println(a);

 }

 

程序输出为:

A initialed
B initialed
A.setB initialed
afterPropertiesSet
init
funb
testspring.A@50d89cB.funb

从这里看到A的name属性在bean加载完成的时候也被成功设置为B的funB方法的返回值了,要点就是用init-method来实现。

加载顺序也可以看到为:

先构造函数——>然后是b的set方法注入——>InitializingBean   的afterPropertiesSet方法——>init-method方法

 

总结为:

以下内容是从书中摘录来的,但是我发现即使摘录一遍,对其内容的理解也会更加深入!  
一、Spring装配Bean的过程   
1. 实例化;  
2. 设置属性值;  
3. 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name;  
4. 如果实现BeanFactoryAware接口,调用setBeanFactory 设置BeanFactory;  
5. 如果实现ApplicationContextAware,调用setApplicationContext设置ApplicationContext  
6. 调用BeanPostProcessor的预先初始化方法;  
7. 调用InitializingBean的afterPropertiesSet()方法;  
8. 调用定制init-method方法;  
9. 调用BeanPostProcessor的后初始化方法;  


Spring容器关闭过程   
1. 调用DisposableBean的destroy();  
2. 调用定制的destroy-method方法;

posted on 2017-07-09 13:14  傻瓜乐园  阅读(488)  评论(0)    收藏  举报

导航