Spring自動(dòng)注入失敗的解決方法
Spring自動(dòng)注入失敗如何解決?
我有一個(gè)被Spring @Service注解的類(MileageFeeCalculator),它有一個(gè)用@Autowired注入的變量(rateService),但是當(dāng)我用這個(gè)變量的時(shí)候,它顯示為null。日志顯示MileageFeeCalculator bean和MileageRateService bean都被創(chuàng)建了,但是當(dāng)我調(diào)用service上的mileageCharge ()方法時(shí),就會(huì)報(bào)NullPointerException錯(cuò)誤。為什么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
}
}
本應(yīng)被注入Service但是并沒(méi)有的類
@Service
public class MileageRateService {
public float ratePerMile() {
return 0.565f;
}
}
為什么我調(diào)用GET /mileage/3這個(gè)請(qǐng)求的時(shí)候,會(huì)報(bào)這樣的錯(cuò)誤:
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是因?yàn)?,Spring無(wú)法獲取你用new關(guān)鍵字創(chuàng)建的類,也無(wú)法自動(dòng)注入它。
Spring Ioc容器有三個(gè)主要的邏輯組件:應(yīng)用程序可以使用的注冊(cè)表(ApplicationContext);通過(guò)把依賴項(xiàng)與上下文中的bean匹配,將依賴的對(duì)象注入的配置器系統(tǒng);以及一個(gè)依賴解析器,它可以查看許多不同bean的配置,并確定如何按必要的順序?qū)嵗团渲盟鼈儭?/p>
Ioc容器并沒(méi)有魔法,除非你以某種方式通知它,否則它無(wú)法獲取Java對(duì)象。當(dāng)你調(diào)用new創(chuàng)建對(duì)象時(shí),JVM實(shí)例化新對(duì)象,并將其中一個(gè)副本交給你——它并不經(jīng)歷Spring的配置過(guò)程。有三種方法可以配置bean實(shí)例。
注入你的bean
最好的選擇是讓Spring注入所有的bean;這樣的代碼量會(huì)最少并且也最容易維護(hù)。為了使注入如你所愿,需要把MileageFeeCalculator像這樣注入。
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
如果你需要為不同的請(qǐng)求都創(chuàng)建一個(gè)類的新實(shí)例,可以通過(guò)Spring注解的scopes實(shí)現(xiàn)。
使用@Configurable
如果你真的需要把new出來(lái)的對(duì)象保存進(jìn)行注入,那可以使用Spring的@Configurable注解,通過(guò)使用AOP在編譯時(shí)織入你的對(duì)象中。這種方法將代碼插入到對(duì)象的構(gòu)造函數(shù)中,提醒Spring這個(gè)對(duì)象正在被創(chuàng)建,這樣Spring就能夠配置新實(shí)例了。這需要你添加一些配置信息。并打開(kāi)Spring的運(yùn)行時(shí)配置處理器。Roo Active Record系統(tǒng)使用這種方法來(lái)允許實(shí)體的new實(shí)例獲取注入的必要持久性信息。
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
手動(dòng)查找bean:不推薦
這種方法只適用于在特殊情況下與遺留代碼對(duì)接。創(chuàng)建一個(gè)Spring可以自動(dòng)注入并且遺留代碼也能調(diào)用的單例適配器總是可取的,但是也許可以直接向spring application context請(qǐng)求bean實(shí)例。
為了做到這點(diǎn),你需要一個(gè)類,該類提供了對(duì)ApplicationContext對(duì)象的引用
@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;
}
}
之后你的遺留代碼就可以調(diào)用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)注入失敗的解決方法的詳細(xì)內(nèi)容,更多關(guān)于Spring自動(dòng)注入失敗的解決的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring和activiti進(jìn)行整合過(guò)程解析
這篇文章主要介紹了Spring和activiti進(jìn)行整合過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
RabbitMQ消息隊(duì)列中多路復(fù)用Channel信道詳解
這篇文章主要介紹了RabbitMQ消息隊(duì)列中多路復(fù)用Channel信道詳解,消息Message是指在應(yīng)用間傳送的數(shù)據(jù),消息可以非常簡(jiǎn)單,比如只包含文本字符串,也可以更復(fù)雜,可能包含嵌入對(duì)象,需要的朋友可以參考下2023-08-08
fastjson全局日期序列化設(shè)置導(dǎo)致JSONField失效問(wèn)題解決方案
這篇文章主要介紹了fastjson通過(guò)代碼指定全局序列化返回時(shí)間格式,導(dǎo)致使用JSONField注解標(biāo)注屬性的特殊日期返回格式失效問(wèn)題的解決方案2023-01-01
SpringBoot的監(jiān)控(Actuator)功能用法詳解
這篇文章主要介紹了SpringBoot的監(jiān)控(Actuator)功能用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
elasticsearch通過(guò)guice注入Node組裝啟動(dòng)過(guò)程
這篇文章主要為大家介紹了?elasticsearch通過(guò)guice注入Node組裝啟動(dòng)過(guò)程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
java子類繼承父類實(shí)例-披薩的選擇實(shí)現(xiàn)代碼
這篇文章主要介紹了java子類繼承父類實(shí)例-披薩的選擇實(shí)現(xiàn)代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
java并發(fā)編程專題(四)----淺談(JUC)Lock鎖
這篇文章主要介紹了java并發(fā)編程(JUC)Lock鎖的相關(guān)內(nèi)容,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-06-06

