Spring高級(jí)接口Aware淺析
Aware 接口功能闡述
Aware 接口提供了一種【內(nèi)置】 的注入手段,例如
a.BeanNameAware 注入 bean 的名字
b.BeanFactoryAware 注入 BeanFactory 容器
c.ApplicationContextAware 注入 ApplicationContext 容器
d.EmbeddedValueResolverAware 注入 ${} 解析器
功能案例演示
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean { private static final Logger log = LoggerFactory.getLogger(MyBean.class); @Override public void setBeanName(String name) { log.debug("當(dāng)前bean " + this + " 名字叫:" + name); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.debug("當(dāng)前bean " + this + " 容器是:" + applicationContext); } @Override public void afterPropertiesSet() throws Exception { log.debug("當(dāng)前bean " + this + " 初始化"); } @Autowired public void aaa(ApplicationContext applicationContext) { log.debug("當(dāng)前bean " + this + " 使用@Autowired 容器是:" + applicationContext); } @PostConstruct public void init() { log.debug("當(dāng)前bean " + this + " 使用@PostConstruct 初始化"); } }
測(cè)試:
GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("myBean", MyBean.class); context.refresh(); context.close();
可能這里有人會(huì)有疑問(wèn): b、c、d 的功能用 @Autowired 就能實(shí)現(xiàn)啊, 為啥還要用 Aware 接口呢
簡(jiǎn)單地說(shuō):
a.@Autowired 的解析需要用到 bean 后處理器, 屬于擴(kuò)展功能
b.而 Aware 接口屬于內(nèi)置功能, 不加任何擴(kuò)展, Spring 就能識(shí)別
某些情況下, 擴(kuò)展功能會(huì)失效, 而內(nèi)置功能不會(huì)失效
如下所示:
@Autowired public void aaa(ApplicationContext applicationContext) { log.debug("當(dāng)前bean " + this + " 使用@Autowired 容器是:" + applicationContext); } @PostConstruct public void init() { log.debug("當(dāng)前bean " + this + " 使用@PostConstruct 初始化"); }
在這里,你會(huì)發(fā)現(xiàn)用 Aware 注入 ApplicationContext 成功, 而 @Autowired 注入 ApplicationContext 失敗
擴(kuò)展功能失效場(chǎng)景分析
@Configuration public class MyConfig1 { private static final Logger log = LoggerFactory.getLogger(MyConfig1.class); @Autowired public void setApplicationContext(ApplicationContext applicationContext) { log.debug("注入 ApplicationContext"); } @PostConstruct public void init() { log.debug("初始化"); } @Bean // beanFactory 后處理器 public BeanFactoryPostProcessor processor1() { return beanFactory -> { log.debug("執(zhí)行 processor1"); }; } }
context.refresh();
這行代碼的執(zhí)行順序,到容器里找到所有的.beanFactory 后處理器來(lái)執(zhí)行,添加 bean 后處理器,初始化單例。
Java 配置類不包含 BeanFactoryPostProcessor 的情況
Java 配置類包含 BeanFactoryPostProcessor 的情況,因此要?jiǎng)?chuàng)建其中的 BeanFactoryPostProcessor 必須提前創(chuàng)建 Java 配置類,而此時(shí)的 BeanPostProcessor 還未準(zhǔn)備好,導(dǎo)致 @Autowired 等注解失效
對(duì)應(yīng)代碼
@Configuration public class MyConfig1 { private static final Logger log = LoggerFactory.getLogger(MyConfig1.class); @Autowired public void setApplicationContext(ApplicationContext applicationContext) { log.debug("注入 ApplicationContext"); } @PostConstruct public void init() { log.debug("初始化"); } @Bean // ?? 注釋或添加 beanFactory 后處理器對(duì)應(yīng)上方兩種情況 public BeanFactoryPostProcessor processor1() { return beanFactory -> { log.debug("執(zhí)行 processor1"); }; } }
注意
解決方法:
- 用內(nèi)置依賴注入和初始化取代擴(kuò)展依賴注入和初始化
- 用靜態(tài)工廠方法代替實(shí)例工廠方法,避免工廠對(duì)象提前被創(chuàng)建
測(cè)試:
GenericApplicationContext context = new GenericApplicationContext(); context.registerBean("myConfig2", MyConfig2.class); context.registerBean(AutowiredAnnotationBeanPostProcessor.class); context.registerBean(CommonAnnotationBeanPostProcessor.class); context.registerBean(ConfigurationClassPostProcessor.class); context.refresh(); context.close();
輸出結(jié)果:
總結(jié)
- Aware 接口提供了一種【內(nèi)置】 的注入手段, 可以注入 BeanFactory, ApplicationContext
- InitializingBean 接口提供了一種【內(nèi)置】的初始化手段
- 內(nèi)置的注入和初始化不受擴(kuò)展功能的影響, 總會(huì)被執(zhí)行, 因此 Spring 框架內(nèi)部的類常用它們
到此這篇關(guān)于Spring高級(jí)接口Aware淺析的文章就介紹到這了,更多相關(guān)Spring Aware內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringMVC學(xué)習(xí)系列之國(guó)際化
這篇文章主要介紹了詳解SpringMVC學(xué)習(xí)系列之國(guó)際化,詳細(xì)的介紹了關(guān)于瀏覽器,Session,Cookie,URL請(qǐng)求的國(guó)際化的實(shí)現(xiàn),有興趣的可以了解一下2017-07-07線程池運(yùn)用不當(dāng)引發(fā)的一次線上事故解決記錄分析
遇到了一個(gè)比較典型的線上問(wèn)題,剛好和線程池有關(guān),另外涉及到死鎖、jstack命令的使用、JDK不同線程池的適合場(chǎng)景等知識(shí)點(diǎn),同時(shí)整個(gè)調(diào)查思路可以借鑒,特此記錄和分享一下2024-01-01java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理分析
這篇文章主要介紹了java內(nèi)存管理關(guān)系及內(nèi)存泄露的原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10Java調(diào)用Oracle存儲(chǔ)過(guò)程詳解
這篇文章主要介紹了Java調(diào)用Oracle存儲(chǔ)過(guò)程詳解的相關(guān)資料,需要的朋友可以參考下2017-02-02基于SpringBoot?使用?Flink?收發(fā)Kafka消息的示例詳解
這篇文章主要介紹了基于SpringBoot?使用?Flink?收發(fā)Kafka消息,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-01-01關(guān)于ArrayList初始化容量的問(wèn)題
這篇文章主要介紹了關(guān)于ArrayList初始化容量的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03Java使用注解實(shí)現(xiàn)防止重復(fù)提交實(shí)例
這篇文章主要介紹了Java使用注解實(shí)現(xiàn)防止重復(fù)提交實(shí)例,在一些項(xiàng)目中由于用戶誤操作,多次點(diǎn)擊表單提交按鈕,會(huì)產(chǎn)生很多次的數(shù)據(jù)交互,為了解決這一問(wèn)題,本文使用注解來(lái)實(shí)現(xiàn)防止重復(fù)提交,需要的朋友可以參考下2023-07-07