背景:是很普通的一个serviceImpl中,一个导入excel接口,中间调用了新增接口,新增接口时mybatis的dao为null,无法插入,很简单但是很不好解决的问题。
最开始我没发现是反射导致的问题, 接下来是我的思考历程。
1、以为是bean容器没有注入,但是另一个serviceImpl也注入了这个Dao,能够成功使用,并且我在项目启动时打印出了所有的bean,确实注入进去了的。
2、我以为是这个类没有初始化,但是这个类也加了@Service注解,应该能够正常使用。
3、最后我发现当单独调用新增接口时能够正常新增,使用导出调用新增时不能正常使用。
然后我试了一下正常的controller依赖注入调用service都可以,使用反射来调用方法的都不能注入,才发现是反射的问题。
因为我写的反射是手动通过反射获得的Bean的实例,这种方式相当于我们new Bean(),此Bean的实例已完全脱离Spring容器,因此无法依赖注入
错误:
//反射, 获取类
Class c = serviceContext.getClass(typeEnum.getCode());
//对类进行实例化
Object o = c.newInstance();
//指定方法
Method method = c.getDeclaredMethod("importFile", MultipartFile.class);
//调用方法
method.invoke(o, new Object[]{file});
正确:修改成从bean容器中拿该类,并实例化,就能够进行依赖注入了。
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextUtil implements ApplicationContextAware {
// Spring应用上下文环境
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的回调方法,设置上下文环境
*
* @param applicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextUtil.applicationContext = applicationContext;
}
/**
* @return ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 获取对象
* @param name
* @return Object
* @throws BeansException
*/
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
public static Object getBean(String name, Class cla) throws BeansException {
return applicationContext.getBean(name, cla);
}
}
//反射, 获取类
Class c = serviceContext.getClass(typeEnum.getCode());
//获取首字母小写类名
String simpleName = c.getSimpleName();
String firstLowerName = simpleName.substring(0,1).toLowerCase() + simpleName.substring(1);
//通过此方法去Spring容器中获取Bean实例
Object o = SpringContextUtil.getBean(firstLowerName, c);
//指定方法
Method method = c.getDeclaredMethod("importFile", MultipartFile.class);
//调用方法
method.invoke(o, new Object[]{file});