引言
最近在優化公司平臺項目,由於該平臺是to B性質,所以有些需求需要 定製化開發,爲了使代碼向上兼容並且更加的靈活,所以用到了反射,但是在使用過程中遇到了@Autowired失效問題。
問題解析:
其實出現這個問題的原因很簡單,就是我們通過獲得的類沒有納入spring容器管理,下面來看一下錯誤代碼:
反射代碼如下:
//爲了測試寫死了
String className ="TaiLongM1CallBackService";
Class c = Class.forName(packagePath + className);
Method m = c.getMethod("callBack", new Class[]{Integer.class});
//設置參數
Object[] arguments = new Object[]{new Integer(robotServiceInfo.getRobotId())};
m.invoke(c.newInstance(), arguments);
通過反射獲得類的方法部分代碼:
@Autowired
private NativeSqlMapper nativeSqlMapper;
@Autowired
private EmailService emailService;
/**
* @Description:
* @author: zhenghao
* @date: 2019/12/13 14:56
*/
public void callBack(Integer robotId) {
String dateStr = DateUtils.getToDayYYYYMMDD();
List<ExcelSheetModel> excelSheetModelList = new ArrayList<>();
//信用卡數據回傳
List<Map<String, Object>> callbackDaily = this.getDailyCallbackData(robotId);
if (callbackDaily == null || callbackDaily.isEmpty()) {
log.info("今日沒有可回傳的數據...");
} else {
。。。。。。。。
當我們運行上面代碼的時候,可以正常獲得類中的 callBack方法,但是當我們debug的進入該方法的時候會發現,我們通過@Autowired注入的類都是空。
看我們反射中的代碼會發現,我們獲得類的方式是 class.newInstance 這中寫法就沒有Spring容器關聯起來獲取bean,雖然也能拿到但是如果類裏面有@Autowired這種方式注入的對象就會空了。
解決方案:
知道錯誤原因了,解決就比較簡單了,我們不要通過class.newInstance方式獲取,而是手動通過spring上下文進行獲取就可以解決這個問題了,修改後的反射代碼
String className ="TaiLongM1CallBackService";
Class c = Class.forName(packagePath + className);
Object obj = ApplicationContextHelper.popBean(c);
Method m = c.getMethod("callBack", new Class[]{Integer.class});
//設置參數
Object[] arguments = new Object[]{new Integer(robotServiceInfo.getRobotId())};
m.invoke(obj, arguments);
增加了手動通過spring上下文獲得類的代碼:
工具類代碼如下:
package com.zqf.common.utils.service;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* @Description: 獲得bean
* @author: zhenghao
* @date: 2019/12/14 12:04
*/
@Service
public class ApplicationContextHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
/**
* 獲取bean
* @param clazz
* @param <T>
* @return
*/
public static <T> T popBean(Class<T> clazz) {
//先判斷是否爲空
if (applicationContext == null) {
return null;
}
return applicationContext.getBean(clazz);
}
public static <T> T popBean(String name, Class<T> clazz) {
if (applicationContext == null) {
return null;
}
return applicationContext.getBean(name, clazz);
}
}
小結
至此,就解決了這個問題,遇到問題我們首先要分析一下出現問題的原因,然後對症下藥,就可以快速解決了