发生背景:开发过程中使用到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);
}
}