发生背景
开发过程中使用到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);
完整代码
package com.vip.vflow2.boot.common.aspect;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.vip.vflow2.boot.common.annotation.ITSMSimpleExport;
import com.vip.vflow2.boot.common.util.EasyExcelUtil;
import com.vip.vflow2.common.po.FileManage;
import com.vip.vflow2.common.po.model.ItilHrProcess;
import com.vip.vflow2.common.service.FileManageService;
import com.vip.vflow2.common.spring.SpringContextUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
/**
* @author ex_zhangheng7
*/
@Aspect
@Component
public class ItsmSimpleExportAspect {
@Autowired
FileManageService service;
@Pointcut("@annotation(com.vip.vflow2.boot.common.annotation.ITSMSimpleExport)")
public void point(){
}
/**
*
* @author ex_zhangheng7
* @date 2021/9/18
* @param point
* @param export
* @return java.lang.Object
*/
@Around("point() && @annotation(export)")
public Object around(ProceedingJoinPoint point, ITSMSimpleExport export){
// 获取注解中传递的查询方法名称
String selectMethod = export.selectMethod();
// 获取注解中传递的查询出list的名称,对应模板中的名称
String listName = export.listName();
// 导出文件的名称
String fileName = export.fileName();
// 导出文件的地址
String templatePath = export.templatePath();
// 获取切面的参数
Object arg = point.getArgs()[0];
// 查询方法执行完成后返回的分页对象
IPage invokeResult;
// 获取切面织入方法对应的参数类型
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
.getMethod().getParameterTypes();
// 获取当前被织入的类
Object target = point.getTarget();
try {
// 从Spring容器中获取类执行对象
Object bean = SpringContextUtil.getBean(getExecuteBeanName(target));
// 获取查询的方法
Method method = bean.getClass().getMethod(selectMethod, parameterTypes);
// 执行查询的方法
invokeResult = (IPage) method.invoke(bean,arg);
// 查询返回的数据
List<ItilHrProcess> processList = invokeResult.getRecords();
// 生成表格
FileManage fileManage = EasyExcelUtil.generatorExportFile(templatePath, processList, listName, fileName);
// 把生成的excel对象存放到数据库,并将生成的id返回到此对象中
service.insert(fileManage);
return fileManage;
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException | NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
/**
* 获取需要执行类的名称
* @author ex_zhangheng7
* @date 2021/9/18
* @param
* @return java.lang.String
*/
private String getExecuteBeanName(Object target){
Objects.requireNonNull(target);
String beanName = target.getClass()
.getAnnotation(Service.class)
.value();
if(Objects.isNull(beanName)){
beanName = target.getClass().getName();
}
return beanName;
}
}
文章思想来源
https://www.jianshu.com/p/2f1f3dc1ad80