迁移到springboot 3后动态方法调用的问题

问题描述 投票:0回答:1

我们目前正在将服务从 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”:“对象不是声明类的实例。”

请帮助解决上述错误。

spring spring-boot reflection spring-transactions spring-boot-3
1个回答
0
投票

您的

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
将识别代理。创建的代理至少应该是类的接口的实现或扩展服务实现。

© www.soinside.com 2019 - 2024. All rights reserved.