我们目前正在将服务从 Spring Boot 2.x 迁移到 Spring Boot 3.2.1 和 java 21 版本,以下代码在 Spring Boot 2.x 中运行良好,但在迁移后遇到了问题。
**Spring Boot 2.x 中的工作代码: **
protected Map<String, Object> returnSavedObject(String packageName, String className, Map<String, Object> requestDto, String moduleName, Long pkId) {
try {
// Dynamically creates module object
Class moduleClass = Class.forName(packageName + className + "Dto");
Object object = returnObjectFromRequest(requestDto, moduleClass, moduleName, pkId);
// Loads bean for the given Module serviceImpl class
Object serviceObject = applicationContext.getBean(className.substring(0, 1).toLowerCase() + className.substring(1) + "ServiceImpl");
// Invokes the save method on serviceImpl class
Object savedObject = serviceObject.getClass().getMethod("save", moduleClass).invoke(serviceObject, object);
log.info("savedObject {}", savedObject);
return fieldHelper.objectToMapConverter(savedObject);
} catch (Exception e) {
throw new NotFoundException(MessageCode.error(ApplicationErrorCode.MODULE_CLASS_NOT_FOUND.getKey(), ApplicationErrorCode.MODULE_CLASS_NOT_FOUND.getValue()));
}
}
**迁移到 Spring Boot 3.2.1 后的问题: **
代码遇到了“java.lang.NoSuchMethodException”异常,在调试过程中,我们观察到“java.lang.NoSuchMethodException:jdk.proxy2.$Proxy292.save(dto)”。看来应用程序上下文中的 getBean 方法返回的是代理 bean,而不是实际的 bean。
为了解决上述问题,我们添加了以下代码来获取实际的 bean 对象。
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(serviceObject);
protected Map<String, Object> returnSavedObject(String packageName, String className, Map<String, Object> requestDto, String moduleName, Long pkId) {
try {
// Dynamically creates module object
Class moduleClass = Class.forName(packageName + className + "Dto");
Object object = returnObjectFromRequest(requestDto, moduleClass, moduleName, pkId);
// Resolves the actual target class from the proxy
String beanClassName = className.substring(0, 1).toLowerCase() + className.substring(1) + "ServiceImpl";
Object serviceObject = applicationContext.getBean(beanClassName);
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(serviceObject);
// Invokes the save method on the target class
Object savedObject = targetClass.getMethod("save", moduleClass).invoke(targetClass, object);
log.info("savedObject {}", savedObject);
return fieldHelper.objectToMapConverter(savedObject);
} catch (Exception e) {
throw new NotFoundException(MessageCode.error(ApplicationErrorCode.MODULE_CLASS_NOT_FOUND.getKey(), ApplicationErrorCode.MODULE_CLASS_NOT_FOUND.getValue()));
}
}
**遇到的新问题: **
更新后的代码现在会抛出“java.lang.IllegalArgumentException”:“对象不是声明类的实例。”
请帮助解决上述错误。
您的
invoke
仍应调用 serviceObject
,因为这就是您想要调用它的地方。我建议使用 Spring 的 ReflectionUtils
代替这个装置,它可以为你处理所有这些事情。
// Dynamically creates module object
var moduleClass = Class.forName(packageName + className + "Dto");
var object = returnObjectFromRequest(requestDto, moduleClass, moduleName, pkId);
// Loads bean for the given Module serviceImpl class
var serviceObject = applicationContext.getBean(className.substring(0, 1).toLowerCase() + className.substring(1) + "ServiceImpl");
// Invokes the save method on serviceImpl class
var saveMethod = ReflectionUtils.findMethod(serviceObject.getClass(), "save", moduleClass);
var savedObject = ReflectionUtils.invokeMethod(saveMethod, serviceObject, object);
log.info("savedObject {}", savedObject);
return fieldHelper.objectToMapConverter(savedObject);
冒昧地让它变得更加 Java 21。查找方法时,
ReflectionUtils
将识别代理。创建的代理至少应该是类的接口的实现或扩展服务实现。