發生背景:開發過程中使用到invoke進行反射調用serviceImpl實現類的方法,在運行中發現採用反射方式調用會導致實現類中@value以及@Autowired註解失效,對應註解值都爲null。
原因:因爲在調用invoke反射方法時,Class是直接使用newInstance靜態方法來實例化對象。所導致對應@value、@Autowired等註解失效。
PS:Spring的註解是在Spring實例化的時候掃描注入,當Spring實例化完畢之後如果再去newInstance一個新的對象顯然是不受Spring管理了,所以相應的註解都是注入爲null。
Class baseService = serviceClassMap.get(taskRecord.getPlateform());
// 獲取指定Method方法
String methodStr = CommonMethodEnum.hasMethod(taskRecord.getType());
Method method = baseService.getMethod(methodStr,Long.class,File.class);
method.invoke(baseService.newInstance(), taskRecord.getId(), file);
解決方案:使用SpringContext上下文獲取對應Bean,從而避免註解失效。
method.invoke(SpringUtil.getBean(baseService), taskRecord.getId(), file);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~SpringUtil工具類~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
採用實現接口ApplicationContextAware從而獲取ApplicationContext
說明:實現該接口的setApplicationContext(ApplicationContext context)方法,並保存ApplicationContext 對象。Spring初始化時,會通過該方法將ApplicationContext對象注入。
public class SpringContextUtil implements ApplicationContextAware {
// Spring應用上下文環境
private static ApplicationContext applicationContext;
/**
* 實現ApplicationContextAware接口的回調方法。設置上下文環境
*
* @param applicationContext
*/
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextUtil.applicationContext = applicationContext;
}
/**
* @return ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 通過name獲取對象
*
* @param name
* @return Object
* @throws BeansException
*/
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
/**
* 通過class獲取對象
*
* @param class
* @return T
* @throws BeansException
*/
public static <T> T getBean(Class<T> clazz) throws BeansException {
return applicationContext.getBean(clazz);
}
}