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

相關文章
相關標籤/搜索