SpringBoot中Aware接口使用及原理解析
Aware接口
在Spring
中存在一個Aware
接口,實現(xiàn)該接口可以讓我們的Bean
獲取到Spring
容器中特定的資源,但該接口只是個標(biāo)記接口
,不存在任何方法,因此我們還需要繼承Aware
來做特定資源獲取的實現(xiàn)。
Spring
中有不少繼承于Aware
的接口的實現(xiàn),比如當(dāng)前Bean
想要獲取環(huán)境變量時,可以實現(xiàn)EnvironmentAware
接口,想要獲取應(yīng)用上下文則可以實現(xiàn)ApplicationContextAware
接口。
常用的Aware實現(xiàn)
接口 | 作用 |
---|---|
BeanClassLoaderAware | 獲得類加載器 |
BeanNameAware | 獲取容器中Bean名稱 |
BeanFactoryAware | 獲取bean創(chuàng)建工廠 |
EnvironmentAware | 獲得環(huán)境變量 |
ResourceLoaderAware | 獲取資源加載器 |
ApplicationEventPublisherAware | 獲取應(yīng)用事件發(fā)布器 |
MessageSourceAware | 獲取文本信息 |
ApplicationContextAware | 獲取當(dāng)前應(yīng)用上下文 |
Aware示例
以下做一個代碼示例,實現(xiàn)EnvironmentAware
接口,獲取到Environment
并嘗試獲取并輸出自定義的屬性。除了Aware
外,還涉及到之前提到的CommandLineRunner 和Property,可以點擊回顧。
創(chuàng)建一個AwareCommandLineRunner
,實現(xiàn)EnvironmentAware
接口,并嘗試獲取并輸出redis-host
屬性
package geek.springboot.application.runner; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Slf4j @Component public class AwareCommandLineRunner implements CommandLineRunner, EnvironmentAware { @Override public void run(String... args) throws Exception { log.info("AwareCommandLineRunner running..."); } @Override public void setEnvironment(Environment environment) { String redisHost = environment.getProperty("redis-host"); log.info("redis-host is {}", redisHost); } }
SpringApplication
啟動代碼如下
package geek.springboot.application; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import java.util.Properties; @Slf4j @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication application = new SpringApplication(Application.class); // 添加redis-host配置 Properties properties = new Properties(); properties.setProperty("redis-host", "127.0.0.1"); application.setDefaultProperties(properties); application.run(args); } }
啟動輸出 2023-08-27 19:01:15.198 INFO 56188 --- [ main] g.s.a.runner.AwareCommandLineRunner : redis-host is 127.0.0.1
自定義Aware
新建一個RedisConfig
配置類
package geek.springboot.application.configuration; import lombok.Data; import org.springframework.stereotype.Component; @Data @Component public class RedisConfig { private String ip = "127.0.0.1"; private Integer port = 6379; @Override public String toString() { return "RedisConfig{" + "ip='" + ip + ''' + ", port=" + port + '}'; } }
創(chuàng)建一個RedisAware
接口,Bean
實現(xiàn)該接口即可獲取RedisConfig
package geek.springboot.application.aware; import geek.springboot.application.configuration.RedisConfig; import org.springframework.beans.factory.Aware; /** * 自定義Aware * * @author Bruse */ public interface RedisAware extends Aware { void setRedisConfig(RedisConfig config); }
創(chuàng)建一個RedisAwareProcessor
,實現(xiàn)BeanPostProcessor
接口,由它具體負(fù)責(zé)將RedisConfig
注入實現(xiàn)了RedisAware
接口的Bean
。 為什么要實現(xiàn)BeanPostProcessor
后邊的原理分析會提及。
package geek.springboot.application.aware; import geek.springboot.application.configuration.RedisConfig; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; /** * 自定義RedisAwareProcessor * * @author Bruse */ @Component public class RedisAwareProcessor implements BeanPostProcessor { @Autowired private ApplicationContext context; @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 判斷當(dāng)前Bean是否實現(xiàn)RedisAware if (bean instanceof RedisAware) { // 強轉(zhuǎn),調(diào)用setRedisConfig方法注入RedisConfig ((RedisAware) bean).setRedisConfig(context.getBean(RedisConfig.class)); } return bean; } }
AwareCommandLineRunner
實現(xiàn)RedisAware
接口
package geek.springboot.application.runner; import geek.springboot.application.aware.RedisAware; import geek.springboot.application.configuration.RedisConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Slf4j @Component public class AwareCommandLineRunner implements CommandLineRunner, EnvironmentAware, RedisAware { @Override public void run(String... args) throws Exception { log.info("AwareCommandLineRunner running..."); } @Override public void setEnvironment(Environment environment) { String redisHost = environment.getProperty("redis-host"); log.info("redis-host is {}", redisHost); } @Override public void setRedisConfig(RedisConfig config) { log.info("redis config: {}", config.toString()); } }
啟動SpringApplication
,輸出如下
2023-08-27 19:08:36.641 INFO 79920 --- [ main] g.s.a.runner.AwareCommandLineRunner : redis config: RedisConfig{ip='127.0.0.1', port=6379}
Aware原理
在AwareCommandLineRunner
的setEnvironment
方法打上斷點,根據(jù)調(diào)用棧可以看到是在ApplicationContextAwareProcessor
的invokeAwareInterfaces()
方法中調(diào)用setEnvironment()
方法進Environment
注入的
接著再往上查找,可以看到invokeAwareInterfaces()
方法又是在postProcessBeforeInitialization()
中調(diào)用的
而ApplicationContextAwareProcessor
正好實現(xiàn)了BeanPostProcessor
接口。這也就是為什么上邊自定義Aware
實現(xiàn)時,需要創(chuàng)建一個RedisAwareProcessor
并實現(xiàn)BeanPostProcessor
的原因
再往上查看調(diào)用棧的話,可以理清完整的從上到下Aware
調(diào)用鏈路
- 調(diào)用
AbstractAutowireCapableBeanFactory
的doCreateBean()
方法 - 調(diào)用
AbstractAutowireCapableBeanFactory
的initializeBean()
方法 - 調(diào)用
AbstractAutowireCapableBeanFactory
的applyBeanPostProcessorsBeforeInitialization()
方法 - 調(diào)用
ApplicationContextAwareProcessor
的postProcessBeforeInitialization()
方法 - 調(diào)用
ApplicationContextAwareProcessor
的invokeAwareInterfaces()
方法 - 調(diào)用
Aware
接口實現(xiàn)的方法
doCreateBean其實涉及到SpringBoot中Bea初始化的內(nèi)容,可以看這一篇SpringBoot Bean實例化流程解析_java_腳本之家 (jb51.net)
以上就是SpringBoot中Aware接口使用及原理解析的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Aware接口的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringCloud OpenFeign與Ribbon客戶端配置詳解
在springcloud中,openfeign是取代了feign作為負(fù)載均衡組件的,feign最早是netflix提供的,他是一個輕量級的支持RESTful的http服務(wù)調(diào)用框架,內(nèi)置了ribbon,而ribbon可以提供負(fù)載均衡機制,因此feign可以作為一個負(fù)載均衡的遠(yuǎn)程服務(wù)調(diào)用框架使用2022-11-11Java中操作Xml使用方法備忘錄(Hutool工具類XmlUtil、XStream)
這篇文章主要給大家介紹了關(guān)于Java中操作Xml使用方法(Hutool工具類XmlUtil、XStream)的相關(guān)資料,XMLUtil是一個工具類,主要用于讀取XML配置文件并提供相應(yīng)的操作方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11Deepin系統(tǒng)安裝eclipse2021-03及CDT插件的安裝教程
本教程教大家deepin20.1操作系統(tǒng)上安裝eclipse_2021-03版的詳細(xì)步驟及CDT插件的安裝方法,通過圖文展示的非常明了,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-06-06Java8之lambda最佳實踐_動力節(jié)點Java學(xué)院整理
在8 里面Lambda是最火的主題,不僅僅是因為語法的改變,更重要的是帶來了函數(shù)式編程的思想,我覺得優(yōu)秀的程序員,有必要學(xué)習(xí)一下函數(shù)式編程的思想以開闊思路2017-06-06SpringBoot接入ftp/ftps并上傳文件和配置的代碼指南
接入ftp服務(wù)器,在springboot上實現(xiàn)起來也不算復(fù)雜,本文主要講下如何在springboot下接入ftp服務(wù)上傳文件,并對出現(xiàn)的問題做一些記錄,ftp服務(wù)的參數(shù)配置等,需要的朋友可以參考下2024-12-12