引言
最近在优化公司平台项目,由于该平台是to B性质,所以有些需求需要 定制化开发,为了使代码向上兼容并且更加的灵活,所以用到了反射,但是在使用过程中遇到了@Autowired失效问题。
问题解析:
其实出现这个问题的原因很简单,就是我们通过获得的类没有纳入spring容器管理,下面来看一下错误代码:
反射代码如下:
//为了测试写死了 String className ="M1CallBackService"; 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 ="M1CallBackService"; 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.jack.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); } }
小结
至此,就解决了这个问题,遇到问题我们首先要分析一下出现问题的原因,然后对症下药,就可以快速解决了