最近在項(xiàng)目中出現(xiàn)了一個(gè)這種情況:我一頓操作猛如虎的寫了好幾個(gè)設(shè)計(jì)模式,然后在設(shè)計(jì)模式中的類中想將數(shù)據(jù)插入數(shù)據(jù)庫,因此調(diào)用Mapper持久層,但是數(shù)據(jù)怎么都寫不進(jìn)去,在我一頓操作猛如虎的查找下,發(fā)現(xiàn)在普通類中用@Autowired
注入的Bean是Null,也就是說注入失敗了,瞎搞。
針對以上情況,我做了三種解決方案,經(jīng)測試均可行,解決方案如下:
- 在設(shè)計(jì)模式中只操作數(shù)據(jù),最后還是將數(shù)據(jù)返回給Controller層,再由Controller向下調(diào)用寫入數(shù)據(jù)庫
- 簡化設(shè)計(jì)模式,然后將其注冊為Service,然后再Service中調(diào)用Mapper層
- 通過Bean工具的方式,在普通類中獲取Bean,然后將內(nèi)容寫入數(shù)據(jù)庫。
經(jīng)過測試,三種情況均可行,最終我選擇了"3"。
- 以下代碼均經(jīng)過我的測試,請放心使用 -
情況復(fù)現(xiàn)
抄作業(yè)可以跳轉(zhuǎn)至正文
情況復(fù)現(xiàn)比較簡單,我們只需要一個(gè)Bean即可,Bean代碼如下:
- Bean代碼
@Component
public class TestComponent {
public String say() {
System.out.println("執(zhí)行成功");
return "執(zhí)行成功";
}
}
在以上代碼中,我們將TestComponent
注冊成為了一個(gè)Bean,為了嚴(yán)禁,我們還需要在Controller中調(diào)用一下這個(gè)類的方法測試一下該類是否真的被注入進(jìn)去了,但是為了文章不要太冗余,這一塊內(nèi)容我省略掉,結(jié)論是:我測試過,是可以在Controller中調(diào)用的。
- 通過普通類調(diào)用該Bean
實(shí)現(xiàn)思想:我們寫一個(gè)普通的類,在Controller中new出該類的對象,然后在該普通類中@Autowired
的方式注入該類并調(diào)用
驗(yàn)證方式:首先,我們會輸出該Bean的地址,如果注入成功的話,我們會得到一長串字符,其次,如果成功的話頁面與控制臺均有輸出
-
Controller層
只寫個(gè)方法了,類信息略
@GetMapping("/com")
public String common() {
CommonClazz clazz = new CommonClazz();
return clazz.say();
}
- 普通類
CommonClazz
public class CommonClazz {
@Autowired
private TestComponent component;
public String say() {
System.out.println("-----Bean:"+component);
return component.say();
}
}
以上代碼中,我們在Controller層new出來了CommonClazz的對象,在CommonClazz中我們Autowired了測試Bean,隨后返回+輸出,一氣呵成,邏輯嚴(yán)謹(jǐn),看似毫無問題,一執(zhí)行滿是BUG,執(zhí)行結(jié)果如下:
頁面:錯(cuò)誤信息,找不到該頁面(其實(shí)是有該路徑,只不過后臺報(bào)錯(cuò)了)
后臺:報(bào)錯(cuò),內(nèi)容如下
可以看到,首先我們對Bean的地址輸出是null
,說明我們注入失敗,什么都沒拿到,因此用null
來執(zhí)行方法會報(bào)錯(cuò)也就可以理解了。
思考一下,如果我這時(shí)候new一個(gè)Service層的實(shí)現(xiàn)類對象,然后調(diào)用Mapper,是否可以將數(shù)據(jù)寫入數(shù)據(jù)庫呢?答案是否定的,因?yàn)閷τ趎ew出來的Service實(shí)現(xiàn)類來說,它也是一個(gè)普通類,而不是Bean,但是Mapper層卻是一個(gè)Bean,這樣又會出現(xiàn)現(xiàn)在的問題。
正文 | 獲取一個(gè)Bean
方式 1 | 通過實(shí)現(xiàn)ApplicationContextAwre方式獲取Bean
!!強(qiáng)烈推薦?。?/b>
這是一種比較推薦的寫法,我們不用再改寫SpringBoot啟動(dòng)類,且獲取Bean的時(shí)候也不用傳入Bean的名稱,只需要傳入一個(gè)
.class
就可以了。
1.1 實(shí)現(xiàn)
SpringContextUtil
代碼如下:
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext ac;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ac = applicationContext;
}
public static <T> T getBean(Class<T> clazz) {
T bean = ac.getBean(clazz);
return bean;
}
}
正如簡介中所說,這種方法不需要修改啟動(dòng)類,我們只需要做這些就可以正常使用了。
1.2 使用
與方式一相比Controller
與CommonClass
類并沒有發(fā)生太大的變化,但是為了更好的閱讀性,我們還是全都展示出來。
- Controller類(依舊省略類信息,只寫方法)
@GetMapping("/com")
public void common() {
CommonClazz clazz = new CommonClazz();
clazz.say();
}
-
CommonClazz
類
public class CommonClazz {
public void say() {
TestComponent bean = SpringContextUtil.getBean(TestComponent.class);
System.out.println("-----Bean:"+bean);
bean.say();
}
}
- Bean類省略,可以去前面復(fù)制
瀏覽器訪問Controller層地址,信息正常輸出,內(nèi)容如下
可以看到Bean的地址被正確輸出(說明不是null),也輸出了Bean中方法的內(nèi)容,說明Bean被正常注入了。
方式 2
!推薦!
這種實(shí)現(xiàn)可以在任意類中獲取一個(gè)Bean,但是要修改SpringBoot啟動(dòng)類,并且在獲取Bean的時(shí)候要傳入兩個(gè)參數(shù),有點(diǎn)冗余,個(gè)人覺得使用起來不如方式1(當(dāng)然也可以通過改寫
getBean()
方法的方式只傳入一個(gè)Bean)。
### 2.1 實(shí)現(xiàn)
- 首先我們要簡單改造一下SpringBoot啟動(dòng)類,變動(dòng)如下:
@SpringBootApplication
public class JimTestApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(JimTestApplication.class, args);
SpringContextUtil.setAc(run);
}
}
- 其次,我們創(chuàng)建一個(gè)
SpringContextUtil
工具類,內(nèi)容如下:
public class SpringContextUtil {
private static ApplicationContext ac;
public static <T> T getBean(String beanName, Class<T> clazz) {
T bean = ac.getBean(beanName, clazz);
return bean;
}
public static void setAc(ApplicationContext applicationContext){
ac = applicationContext;
}
}
**大功告成!**接下來只需要在普通類中調(diào)用該工具類中的方法,就可以獲得一個(gè)Bean了,接下來我們測試一下、
測試思路:與上面一樣,我們通過Controller new普通類對象,然后在普通類對象中通過這個(gè)工具類獲取一個(gè)Bean,并且輸出Bean的地址以及調(diào)用Bean的方法
為了方便測試,所有的方法都不加返回值了,直接輸出 ,后面也是如此。
2.2 使用
- Controller類
new CommonClazz()
(依舊省略類信息,直接寫方法)
@GetMapping("/com")
public void common() {
CommonClazz clazz = new CommonClazz();
clazz.say();
}
-
CommonClazz
類信息如下
public class CommonClazz {
public void say() {
// 使用如下
TestComponent bean = SpringContextUtil.getBean("testComponent",TestComponent.class);
System.out.println("-----Bean:"+bean);
bean.say();
}
}
-
Bean(TestComponent)
沒有做多大的改動(dòng),只是有返回值改成void了,為了節(jié)省篇幅,這里也省略不寫了。
我們在瀏覽器調(diào)用Controller的地址之后,控制臺得到如下輸出:
結(jié)論:Bean被正確注入
方式 3 | 繼承ApplicationObjectSupport的方式獲取Bean
!!不推薦!!
這是一種比較雞肋的方法,使用起來有很大的局限性:它只能在Bean中使用。因?yàn)樗旧硪残枰鳛锽ean被注入后才能生效。
3.1 實(shí)現(xiàn)
-
SpringContextUtil
類內(nèi)容如下
@Service
public class SpringContextUtil extends ApplicationObjectSupport {
public <T> T getBean(Class<T> clazz) {
T bean = getApplicationContext().getBean(clazz);
return bean;
}
}
3.2 測試
老樣子,為了方便閱讀,我決定省略測試內(nèi)容,直接說測試結(jié)果。
- 在普通類中使用,失敗,獲取的測試Bean是一個(gè)
null
- 在Controller中直接將該類作為Bean
@Autowired
進(jìn)去(因?yàn)?code>@Service注解就想到了),獲取Bean成功 - 我也嘗試了一些其他的辦法在普通類中使用,均失敗了,有好辦法的話告訴我吧。
方式 4 | 繼承WebApplicationObjectSupport
??!不推薦!!
與**[方式3]**一樣,它也只能在Bean中使用,因此也很不推薦。
### 4.1 實(shí)現(xiàn)
@Service
public class SpringContextUtil extends WebApplicationObjectSupport {
public <T> T getBean(Class<T> clazz) {
T bean = getApplicationContext().getBean(clazz);
return bean;
}
}
4.2 測試
同[方式3],略。
方式 5 | 通過WebApplicationContextUtils
??!不推薦!!
適用于web項(xiàng)目的b/s結(jié)構(gòu)。只適合獲取web項(xiàng)目中。
補(bǔ)充:該bean 定義對應(yīng)于單個(gè)
websocket
的生命周期。該作用域僅適用于WebApplicationContext
環(huán)境。
5.1 實(shí)現(xiàn)
-
SpringContextUtil
代碼
public class SpringContextUtil {
public static <T> T getBean(ServletContext request, String name, Class<T> clazz){
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request);
// 或者
WebApplicationContext webApplicationContext1 = WebApplicationContextUtils.getWebApplicationContext(request);
// webApplicationContext1.getBean(name, clazz)
T bean = webApplicationContext.getBean(name, clazz);
return bean;
}
}
5.2 測試
- 首先第一個(gè)參數(shù)不能傳遞
null
,否則會報(bào)錯(cuò) - 暫時(shí)沒有這種場景,后面我就沒測(偷懶
文章來源:http://www.zghlxwxcb.cn/news/detail-805875.html
致謝
感謝 華為云 | springboot獲取bean的幾種常用方式 對本博客的幫助文章來源地址http://www.zghlxwxcb.cn/news/detail-805875.html
到了這里,關(guān)于[SpringBoot]如何在一個(gè)普通類中獲取一個(gè)Bean的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!