Spring ApplicationContext 容器可以加載配置文件中定義的 bean,將所有的 bean 集中在一起,當有請求的時候分配 bean。如果說BeanFactory是Spring的心臟,那么ApplicationContext就是完整的身軀了。ApplicationContext由BeanFactory派生而來,提供了更多面向實際應用的功能。另外,它增加了企業所需要的功能,比如,從屬性文件中解析文本信息和將事件傳遞給所指定的監聽器。這個容器在 org.springframework.context.ApplicationContext interface 接口中定義。
ApplicationContext的初始化和BeanFactory有一個重大的區別:BeanFactory在初始化容器時,並未實例化Bean,直到第一次訪問某個Bean時才實例目標Bean;而ApplicationContext則在初始化應用上下文時就實例化所有單實例的Bean。因此ApplicationContext的初始化時間會比BeanFactory稍長一些,不過稍后的調用則沒有這樣的缺陷了。
傳統的獲取ApplicationContext的方式有很多種,下面小編簡單地介紹幾種常用的方式!在獲取ApplicationContext實例后,就可以調用getBean(beanName)返回Bean了。
為了驗證,假設已經構建了Spring Boot項目,在包com.eg.wiener.config中新增測試類。
package com.eg.wiener.config; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; @Service public class BeanTest { @Bean public BeanTest getBeanObj() { BeanTest bean = new BeanTest(); System.out.println("調用方法:" + bean); return bean; } }
直接注入
@Autowired private ApplicationContext ctx; @GetMapping("/getContext") public String getContext(){ Object bean1 = ctx.getBean("getBeanObj"); return String.format(" ctx 打印bean %s", bean1); }
啟動項目,可以找到日志:
2020-06-27 10:50:16.879 INFO 12272 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2187 ms 調用方法:com.eg.wiener.config.BeanTest@3c74aa0d
說明bean已經被注入Spring容器,默認bean的名稱就是其方法名。在瀏覽器訪問函數getContext() 時,會返回bean【getBeanObj】的信息:
ctx 打印bean com.eg.wiener.config.BeanTest@3c74aa0d
和啟動時日志打印的bean 信息一致,而且,沒有執行方法getBeanObj()。
實現ApplicationContextAware接口
創建一個實體類並實現ApplicationContextAware接口,重寫接口內的setApplicationContext方法來完成獲取ApplicationContext實例的方法,代碼如下所示:
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class ApplicationContextProvider implements ApplicationContextAware { /** * 上下文對象實例 */
private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * 獲取applicationContext * * @return
*/
public ApplicationContext getApplicationContext() { return applicationContext; } /** * 通過name獲取 Bean. * * @param name * @return
*/
public Object getBean(String name) { return getApplicationContext().getBean(name); } /** * 通過class獲取Bean. * * @param clazz * @param <T> * @return
*/
public <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } /** * 通過name,以及Clazz返回指定的Bean * * @param name * @param clazz * @param <T> * @return
*/
public <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
在拿到ApplicationContext對象實例后就可以獲取Bean的注入實例對象,在ApplicationContextProvider類內簡單的實現了幾個方法來獲取指定的Bean實例,也可以添加更多的方法來完成更多的業務邏輯。
這里要注意ApplicationContextProvider類上的@Component注解是不可以去掉的,去掉后Spring就不會自動調用setApplicationContext方法來為我們設置上下文實例。我簡單的創建了一個API,以便測試,效果可以達到要求,代碼如下:
@Autowired private ApplicationContextProvider provider; @GetMapping("/getContextProd") public String getContextProd(){ Object bean = provider.getBean("getBeanObj"); return String.format(" ApplicationContextProvider 打印bean %s", bean); }
在自定義AutoConfiguration中獲取
有時候我們需要實現自定義的Spring starter,並在自定義的AutoConfiguration中使用ApplicationContext,Spring在初始化AutoConfiguration時會自動傳入ApplicationContext,這時我們就可以使用下面的方式來獲取ApplicationContext:
@Configuration @EnableFeignClients("com.yidian.data.interfaces.client") public class FeignAutoConfiguration { FeignAutoConfiguration(ApplicationContext context) { // 在初始化AutoConfiguration時會自動傳入ApplicationContext
doSomething(context); }}
啟動時獲取ApplicationContext
在啟動Spring Boot項目時,需要調用SpringApplication.run()方法,而run()方法的返回值就是ApplicationContext,我們可以把run()方法返回的ApplicationContext對象保存下來,方便隨時使用。下面使用這個返回示例獲取Bean示例:
private static ApplicationContext applicationContext; public static void main(String[] args) { applicationContext = SpringApplication.run(WienerApplication.class, args); Object bean1 = applicationContext.getBean("getBeanObj"); System.out.println(String.format("打印bean1 %s", bean1)); bean1 = applicationContext.getBean("getBeanObj"); System.out.println(String.format("打印bean2 %s", bean1)); }
項目啟動后,在日志中可以發現如下三條記錄:
調用方法:com.eg.wiener.config.BeanTest@3c74aa0d
打印bean1 com.eg.wiener.config.BeanTest@3c74aa0d
打印bean2 com.eg.wiener.config.BeanTest@3c74aa0d
通過WebApplicationContextUtils獲取
Spring提供了一個工具類WebApplicationContextUtils用於獲取ApplicationContext對象,它是Spring框架基礎包中的類,該方法必須依賴Servlet容器。
WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc);
WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);
測試用例:
關於以上5種獲取ApplicationContext上下文對象實例的方式,大家有什么看法,歡迎留言討論,也希望大家多多點贊,祝各位生活愉快。
Reference
https://www.jianshu.com/p/ef7739a01cb0
