- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- Spring自動(dòng)注入失敗的解決方法
我有一個(gè)被Spring @Service注解的類(lèi)(MileageFeeCalculator),它有一個(gè)用@Autowired注入的變量(rateService),但是當我用這個(gè)變量的時(shí)候,它顯示為null。日志顯示MileageFeeCalculator bean和MileageRateService bean都被創(chuàng )建了,但是當我調用service上的mileageCharge ()方法時(shí),就會(huì )報NullPointerException錯誤。為什么Spring不能自動(dòng)注入這個(gè)實(shí)例?
Controller:
@Controller public class MileageFeeController { @RequestMapping("/mileage/{miles}") @ResponseBody public float mileageFee(@PathVariable int miles) { MileageFeeCalculator calc = new MileageFeeCalculator(); return calc.mileageCharge(miles); } }
Service:
@Service public class MileageFeeCalculator { @Autowired private MileageRateService rateService; // <--- should be autowired, is null public float mileageCharge(final int miles) { return (miles * rateService.ratePerMile()); // <--- throws NPE } }
本應被注入Service但是并沒(méi)有的類(lèi)
@Service public class MileageRateService { public float ratePerMile() { return 0.565f; } }
為什么我調用GET /mileage/3這個(gè)請求的時(shí)候,會(huì )報這樣的錯誤:
java.lang.NullPointerException: null at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13) at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14) ...
@Autowired注解的字段為null是因為,Spring無(wú)法獲取你用new關(guān)鍵字創(chuàng )建的類(lèi),也無(wú)法自動(dòng)注入它。
Spring Ioc容器有三個(gè)主要的邏輯組件:應用程序可以使用的注冊表(ApplicationContext);通過(guò)把依賴(lài)項與上下文中的bean匹配,將依賴(lài)的對象注入的配置器系統;以及一個(gè)依賴(lài)解析器,它可以查看許多不同bean的配置,并確定如何按必要的順序實(shí)例化和配置它們。
Ioc容器并沒(méi)有魔法,除非你以某種方式通知它,否則它無(wú)法獲取Java對象。當你調用new創(chuàng )建對象時(shí),JVM實(shí)例化新對象,并將其中一個(gè)副本交給你——它并不經(jīng)歷Spring的配置過(guò)程。有三種方法可以配置bean實(shí)例。
最好的選擇是讓Spring注入所有的bean;這樣的代碼量會(huì )最少并且也最容易維護。為了使注入如你所愿,需要把MileageFeeCalculator像這樣注入。
@Controller public class MileageFeeController { @Autowired private MileageFeeCalculator calc; @RequestMapping("/mileage/{miles}") @ResponseBody public float mileageFee(@PathVariable int miles) { return calc.mileageCharge(miles); } }
如果你需要為不同的請求都創(chuàng )建一個(gè)類(lèi)的新實(shí)例,可以通過(guò)Spring注解的scopes實(shí)現。
如果你真的需要把new出來(lái)的對象保存進(jìn)行注入,那可以使用Spring的@Configurable注解,通過(guò)使用AOP在編譯時(shí)織入你的對象中。這種方法將代碼插入到對象的構造函數中,提醒Spring這個(gè)對象正在被創(chuàng )建,這樣Spring就能夠配置新實(shí)例了。這需要你添加一些配置信息。并打開(kāi)Spring的運行時(shí)配置處理器。Roo Active Record系統使用這種方法來(lái)允許實(shí)體的new實(shí)例獲取注入的必要持久性信息。
@Service @Configurable public class MileageFeeCalculator { @Autowired private MileageRateService rateService; public float mileageCharge(final int miles) { return (miles * rateService.ratePerMile()); } }
這種方法只適用于在特殊情況下與遺留代碼對接。創(chuàng )建一個(gè)Spring可以自動(dòng)注入并且遺留代碼也能調用的單例適配器總是可取的,但是也許可以直接向spring application context請求bean實(shí)例。
為了做到這點(diǎn),你需要一個(gè)類(lèi),該類(lèi)提供了對ApplicationContext對象的引用
@Component public class ApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } public static ApplicationContext getContext() { return context; } }
之后你的遺留代碼就可以調用getContext()方法獲取所需的bean實(shí)例了。
@Controller public class MileageFeeController { @RequestMapping("/mileage/{miles}") @ResponseBody public float mileageFee(@PathVariable int miles) { MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class); return calc.mileageCharge(miles); } }
以上就是Spring自動(dòng)注入失敗的解決方法的詳細內容,更多關(guān)于Spring自動(dòng)注入失敗的解決的資料請關(guān)注腳本之家其它相關(guān)文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站