Spring bean 加载顺序


#Spring#


示例1

项目结构

demo01 包结构:

src/main/java/demo01
├── Demo01Main.java
├── TestBean01.java
├── TestBean02.java
└── TestBean03.java

TestBean01.java

TestBean01 类内容:

package demo01;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class TestBean01 implements InitializingBean, ApplicationContextAware, ApplicationListener {
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println(this.getClass().getCanonicalName() + " afterPropertiesSet");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(this.getClass().getCanonicalName() + " setApplicationContext");
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println(this.getClass().getCanonicalName() + " event: " + event.getClass().getCanonicalName());
    }

}

TestBean02.java、TestBean03.java

TestBean02、TestBean03 内容和 TestBean01 相同。

Demo01Main.java

Demo01Main 类内容:

package demo01;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class Demo01Main {

    @Test
    public void test01() {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Demo01Main.class);
        System.out.println("finish");

    }

    @Test
    public void test02() {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Demo01Main.class);
        ctx.start();
        System.out.println("finish");

    }

}

执行 test01 函数,结果为:

demo01.TestBean01 setApplicationContext
demo01.TestBean01 afterPropertiesSet
demo01.TestBean02 setApplicationContext
demo01.TestBean02 afterPropertiesSet
demo01.TestBean03 setApplicationContext
demo01.TestBean03 afterPropertiesSet
demo01.TestBean01  event: org.springframework.context.event.ContextRefreshedEvent
demo01.TestBean02  event: org.springframework.context.event.ContextRefreshedEvent
demo01.TestBean03  event: org.springframework.context.event.ContextRefreshedEvent
finish

执行 test02 函数,结果为:

demo01.TestBean01 setApplicationContext
demo01.TestBean01 afterPropertiesSet
demo01.TestBean02 setApplicationContext
demo01.TestBean02 afterPropertiesSet
demo01.TestBean03 setApplicationContext
demo01.TestBean03 afterPropertiesSet
demo01.TestBean01 event: org.springframework.context.event.ContextRefreshedEvent
demo01.TestBean02 event: org.springframework.context.event.ContextRefreshedEvent
demo01.TestBean03 event: org.springframework.context.event.ContextRefreshedEvent
demo01.TestBean01 event: org.springframework.context.event.ContextStartedEvent
demo01.TestBean02 event: org.springframework.context.event.ContextStartedEvent
demo01.TestBean03 event: org.springframework.context.event.ContextStartedEvent
finish

当 Spring 初始化完毕后,会发布 ContextRefreshedEvent 事件。

在初始化一个 bean 时,ApplicationContextAware 的 setApplicationContext 方法比 InitializingBean 的 afterPropertiesSet 方法优先执行。

调用 AnnotationConfigApplicationContext 的 start 方法时候,会发布 ContextStartedEvent 事件,用于通知 spring 已经启动好了。

示例2

项目结构

demo02 包结构如下:

src/main/java/demo02
├── Demo02Main.java
├── TestBean01.java
├── TestBean02.java
└── TestBean03.java

TestBean01.java

TestBean01 内容如下:

package demo02;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class TestBean01 implements InitializingBean, ApplicationContextAware, ApplicationListener {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println(this.getClass().getCanonicalName() + " afterPropertiesSet");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(this.getClass().getCanonicalName() + " setApplicationContext");
        applicationContext.getBean(TestBean03.class);  // 获取 TestBean03 bean
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println(this.getClass().getCanonicalName() + " event: " + event.getClass().getCanonicalName());
    }
}

TestBean02.java

TestBean02 类内容如下:

package demo02;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class TestBean02 implements InitializingBean, ApplicationContextAware, ApplicationListener {


    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println(this.getClass().getCanonicalName() + " afterPropertiesSet");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(this.getClass().getCanonicalName() + " setApplicationContext");
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println(this.getClass().getCanonicalName() + " event: " + event.getClass().getCanonicalName());
    }

}

TestBean03.java

TestBean03 和 TestBean02 内容相同。

Demo02Main.java

Demo02Main 类内容如下:

package demo02;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class Demo02Main {

    @Test
    public void test01() {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Demo02Main.class);
        System.out.println("finish");

    }

}

执行 test01 ,结果为:

demo02.TestBean01 setApplicationContext
demo02.TestBean03 setApplicationContext
demo02.TestBean03 afterPropertiesSet
demo02.TestBean01 afterPropertiesSet
demo02.TestBean02 setApplicationContext
demo02.TestBean02 afterPropertiesSet
demo02.TestBean03 event: org.springframework.context.event.ContextRefreshedEvent
demo02.TestBean01 event: org.springframework.context.event.ContextRefreshedEvent
demo02.TestBean02 event: org.springframework.context.event.ContextRefreshedEvent
finish

在初始化 TestBean01 时,setApplicationContext 方法中尝试获取 TestBean03 的 bean,于是 TestBean03 打断了 TestBean01 初始化,等 TestBean03 初始化完毕后,TestBean01 继续初始化。然后 TestBean02 初始化。

从这里可以推论:spring 先扫描所有的要处理的类,记录下来,然后一个个初始化。


( 本文完 )