springboot bean加载顺序分析

spring容器载入bean顺序是不肯定的,spring框架没有约定特定顺序逻辑规范。但spring保证若是A依赖B(如beanA中有@Autowired B的变量),那么B将先于A被加载。但若是beanA不直接依赖B,咱们如何让B仍先加载呢?spring

须要的场景距离以下数组

  1. bean A 间接(并非直接@Autowired)依赖 bean B。如bean A有一个属性,须要在初始化的时候对其进行赋值(须要在初始化的时候作,是由于这个属性实际上是包装了其它的几个Bean的,好比说代理了Bean B),因此这就造成了Bean A间接的依赖Bean B了
  2. bean A是事件发布者(或JMS发布者),bean B (或一些) 负责监听这些事件,典型的如观察者模式。咱们不想B 错过任何事件,那么B须要首先被初始化。

以上是两种典型的,Bean初始化的时候存在依赖关系的状况,均可以经过@DependsOn来解决 。app

例子框架

准备工做:(两个controller和一个service)函数

@Controller
public class HelloController {
	public HelloController() {
        System.out.println("HelloController 初始化。。。");
    }
    @ResponseBody
    @GetMapping("/hello")
    public String helloGet() throws Exception {
        return "hello...Get";
    }
}

@Controller
public class AsyncHelloController {
	public AsyncHelloController() {
        System.out.println("AsyncHelloController 初始化。。。");
    }
}

@Service
public class HelloServiceImpl implements HelloService {
    public HelloServiceImpl() {
        System.out.println("HelloServiceImpl 初始化。。。");
    }	
}

启动容器,打印顺序(初始化顺序以下:)spa

HelloServiceImpl 初始化。。。
AsyncHelloController 初始化。。。
HelloController 初始化。。。

须要注意的是:这个demo的日志都是放在默认的构造函数里面的,所以即便你使用了@Autowired,也是不会打乱构造函数的执行顺序的,由于,由于@Autowired的解析发生在给属性赋值的populate()方法里,这个时候本身已经实例化了,才会去给属性赋值, 因此若是你要求的时机稍微比较晚能够在赋值期间、或者实例化期间。代理

@DependsOn:让HelloController在AsyncHelloController以前实例化

//@DependsOn // 这里面写String数组。不写不会生效,可是若写了,名字要写正确,不然会报错的
@DependsOn({"helloController"}) // 名称必须写对,必须是容器里存在的Bean,不然启动报错的(fast-fail是好事)
@Controller
public class AsyncHelloController {
	...
}

HelloServiceImpl 初始化。。。
HelloController 初始化。。。   --> HelloController先被实例化了~~~
AsyncHelloController 初始化。。。

使用@Lazy间接实现日志

@Lazy
public class AsyncHelloController {
	...
}

HelloServiceImpl 初始化。。。
HelloController 初始化。。。

咱们发现它只有两句输出,这个时候AsyncHelloController尚未实例化。只有首次访问它的时候才会实例化,因此咱们是经过间接的方式实现了这个效果。code

相关文章
相关标签/搜索