@PostConstruct及跳坑記錄
@PostConstruct的一個控制方法加載順序的一個注解,如果使用恰當,可以方便解決很多問題,如果使用不當,也會出現一些認為莫名其妙的問題。
這里說一下@PostConstruct和@Autowired 一起使用的一些問題。
首先@PostConstruct是javax.annotation包下的注解,並不是Spring提供的。看一下servlet中的加載順序。
graph TB 服務器加載Sevlet-->Servlet-Construct Servlet-Construct-->PostConstruct PostConstruct-->init init-->service service-->destroy destroy-->PreDestroy PreDestroy-->服務器卸載sevlet完畢
再來看一下Spring中的加載順序:
graph LR Construct-->Autowired Autowired-->PostConstruct
- @Autowired是在構造方法執行之后開始執行的
- @PostConstruct是在依賴注入完成后開始執行
舉一個跳坑的例子
場景
兩個service:Aservice和Bservice,一個bean:Cbean;
在Bservice中的@PostConstruct方法中動態注入一個對象Cbean,Aservice中需要依賴Cbean。
跳坑演示
public class Cbean {
private int id;
private String name;
}
Bservie中的一個PostConstruct方法動態注冊Cbean到spring中
@Component
public class Bservie {
@Autowired
private ApplicationContext context;
@PostConstruct
public void init() {
Cbean c = new Cbean();
c.setId(1);
c.setName("name");
//獲取BeanFactory
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
//動態注冊bean.
defaultListableBeanFactory.registerSingleton("cbean",c);
}
}
Aservice中需要注入Cbean
@Component
public class Asevice {
@Autowired
private Cbean cbean;
@Autowired
private Bservie bservie;
}
這里的AService的加載順序為:構造器-->Autowired Cbean;
此時Bservice中的PostConstruct還沒有觸發執行,所以spring池中沒有Cbean,自然拋出異常:
Field cbean in com.xplan.testpostconstruct.Asevice required a bean of type 'com.xplan.testpostconstruct.Cbean' that could not be found.
當然,如Aservice中有多個Autowired,加載順序是從上到下的。
這個困局的解法只需要把Aservice中的兩個屬性調整下順序即可,這樣就先加載Bservie,在創建Bservie的過程中會觸發PostConstruct的方法,自然此局就解了。
@Component
public class Asevice {
@Autowired
private Bservie bservie;
@Autowired
private Cbean cbean;
}
通過這個示例,可以體會一下這些注解之間的微妙關系。
世界上所有的坑都是自己的無知造成的,想要避坑,就得不斷提高自己的道行。
CLC
