Spring中单个bean的加载步骤
Spring框架中对于单个bean生成其实例时,需要经过一系列步骤。
其每个步骤一般都是实现某个接口,或者配置指定某个方法(如指定init方法)来达到目的。
可以编写一个bean,实现所有要测试的接口,配置指定的方法,来观察其执行顺序。
网上查阅相关资料,相关文章转发如下:
以下内容转自:http://blog.csdn.net/hsgao_water/article/details/52402264
在验证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之后。
代码:
- <span style="font-size:14px;">package cn.com.init;
- 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.beans.factory.config.BeanFactoryPostProcessor;
- import org.springframework.beans.factory.config.BeanPostProcessor;
- import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
- public class HelloWorld implements InitializingBean, BeanPostProcessor, BeanFactoryPostProcessor, BeanFactoryAware,
- BeanNameAware, DisposableBean {
- public HelloWorld() {
- System.out.println("调用HelloWorld构造器...");
- }
- private String hello;
- public String getHello() {
- return hello;
- }
- public void setHello(String hello) {
- this.hello = hello;
- System.out.println("调用setHello()...");
- }
- @Override
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
- System.out.println("调用BeanPostProcessor的postProcessBeforeInitialization()...");
- return bean;
- }
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- System.out.println("调用BeanPostProcessor的postProcessAfterInitialization()...");
- return bean;
- }
- @Override
- public void afterPropertiesSet() throws Exception {
- System.out.println("调用InitializingBean的afterPropertiesSet()...");
- }
- @Override
- public void postProcessBeanFactory(ConfigurableListableBeanFactory paramConfigurableListableBeanFactory)
- throws BeansException {
- System.out.println("调用BeanFactoryPostProcessor的postProcessBeanFactory()...");
- }
- @Override
- public String toString() {
- return "HelloWorld [hello=" + hello + "]";
- }
- @Override
- public void setBeanName(String paramString) {
- System.out.println("调用BeanNameAware.setBeanName");
- }
- @Override
- public void setBeanFactory(BeanFactory paramBeanFactory) throws BeansException {
- System.out.println("调用BeanFactoryAware.setBeanFactory");
- }
- @Override
- public void destroy() throws Exception {
- System.out.println("DisposableBean 接口 destroy方法");
- }
- public void init() throws Exception {
- System.out.println("HelloWorld类init 方法");
- }
- }
- </span>
配置文件:
- <span style="font-size:14px;"><?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:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- 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
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"
- default-lazy-init="false">
- <!-- <bean id="myJavaBean" class=" cn.com.init.MyJavaBean" init-method="initMethod">
- <property name="desc" value="原始的描述信息" />
- <property name="remark" value="原始的备注信息" />
- </bean>
- <bean id="myBeanPostProcessor" class=" cn.com.init.MyBeanPostProcessor" />
- <bean id="myBeanFactoryPostProcessor" class=" cn.com.init.MyBeanFactoryPostProcessor" /> -->
- <bean id="hello" class="cn.com.init.HelloWorld" init-method="init" >
- <property name="hello" value="hello" />
- </bean>
- </beans></span>
测试方法:
- <span style="font-size:14px;">package mybatis;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import cn.com.init.HelloWorld;
- import junit.framework.TestCase;
- public class BeanPostPorcessorTest extends TestCase {
- private ClassPathXmlApplicationContext context;
- protected void setUp() throws Exception {
- super.setUp();
- String[] paths = {"classpath*:spring-text.xml"};
- context = new ClassPathXmlApplicationContext(paths);
- }
- public void testBeanFactoryPostProcessor()
- {
- HelloWorld bean = (HelloWorld) context.getBean("hello");
- System.out.println(bean);
- context.getBeanFactory().destroySingletons();
- }
- }
- </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 的执行顺序。
- public class A implements InitializingBean {
- private B b;
- private String name; // = b.funb();
- public void setB(B b) {
- System.out.println("A.setB initialed");
- this.b = b;
- }
- public A() {
- System.out.println("A initialed");
- }
- public void init() {
- System.out.println("init");
- this.name = b.funb();
- }
- @Override
- public String toString() {
- return super.toString() + this.name;
- }
- public void afterPropertiesSet() throws Exception {
- //其实放在这里也可以
- //this.name = b.funb();
- System.out.println("afterPropertiesSet");
- }
- }
- public class B {
- public String funb() {
- System.out.println("funb");
- return "B.funb";
- }
- public B() {
- System.out.println("B initialed");
- }
- }
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方法;
浙公网安备 33010602011771号