原创

SpringBoot-通过反射方式调用无依赖模块中的方法

1. 调用示例

private static final String COMMON_TASK_HANDLER_BEAN_NAME = "cn.jiangjiesheng.ecp.schedule.CommonTaskHandler";

try {
    //有依赖时通过此方案获取: XxlJobRetry xxlJobRetry = (XxlJobRetry) BeansTool.getBean(sysRetryTask.getBeanName());
    Object instance = InstanceCache.getOrCreateInstance(true, COMMON_TASK_HANDLER_BEAN_NAME);
    ReflectUtils.getInstance().invokeMethod(COMMON_TASK_HANDLER_BEAN_NAME, "execute", instance, finalTaskNum);
} catch (Exception e) {
    Log.showRedHighLightLog(true, LOG_TAG, "异步立即调用下载任务失败", e);
}

2. 代码文件

InstanceCache.java

package cn.jiangjiesheng.core.utils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * // 示例1:从 Spring 容器中获取或创建一个实例(推荐用于 Spring 管理的类)
 * Object instance1 = InstanceCache.getOrCreateInstance(true, "com.example.ecpweb.CommonTaskHandler");
 *
 * // 示例2:通过反射构造函数创建实例(适用于非 Spring 类)
 * Object instance2 = InstanceCache.getOrCreateInstance(false, "com.example.NonSpringClass");
 *
 * // 示例3:带参数的构造方法(只在 useSpring = false 时生效)
 * Object instance3 = InstanceCache.getOrCreateInstance(false, "com.example.MyService", "Tom", 25);
 */
public class InstanceCache {
    private static final Map<String, Object> instances = new ConcurrentHashMap<>();

    public static Object getOrCreateInstance(boolean useSpring, String className, Object... args) throws Exception {
        if (instances.containsKey(className)) {
            return instances.get(className);
        }
        Object instance = ReflectUtils.getInstance().createInstance(useSpring, className, args);
        instances.put(className, instance);
        return instance;
    }
}

ReflectUtils.java

package cn.jiangjiesheng.core.utils;

import cn.hutool.extra.spring.SpringUtil;
import com.envtoday.ecp.exception.GnException;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * //  场景一:创建 Spring 管理的 Bean(自动注入依赖)
 * Object instance = ReflectUtils.getInstance().createInstance(
 *     true,
 *     "com.example.ecpweb.CommonTaskHandler"
 * );
 *
 * //  场景二:创建普通类(含构造参数)
 * // 假设有类:MyService(String name, int age)
 * Object instance = ReflectUtils.getInstance().createInstance(
 *     false,
 *     "com.example.MyService",
 *     "Tom",
 *     25
 * );

 */
public class ReflectUtils {

    // 单例模式(可选)
    private static final ReflectUtils INSTANCE = new ReflectUtils();

    public static ReflectUtils getInstance() {
        return INSTANCE;
    }

    private ReflectUtils() {}

    /**
     * 加载类
     */
    public Class<?> loadClass(String className) throws ClassNotFoundException {
        return Class.forName(className);
    }

    /**
     * 创建类的实例(支持 Spring 管理的 Bean 和普通类)
     *
     * @param useSpring 是否使用 Spring 容器获取 Bean
     * @param className 类名
     * @param args      构造参数(可选)
     * @return 实例对象
     */
    public Object createInstance(boolean useSpring, String className, Object... args) throws Exception {
        Class<?> clazz = loadClass(className);

        if (useSpring) {
            try {
                // 尝试从 Spring 容器中获取 Bean (package cn.hutool.extra.spring;)
                return SpringUtil.getBean(clazz);
            } catch (Exception e) {
                // 如果不是 Spring Bean,或者找不到对应的 Bean,尝试回退到反射创建
                throw new GnException("Spring 环境中没有此bean:"+className);
            }
        }

        // 如果不是 Spring Bean 或者 Spring 获取失败,则使用反射创建
        if (args == null || args.length == 0) {
            // 无参构造函数
            Constructor<?> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            return constructor.newInstance();
        } else {
            // 有参构造函数
            Class<?>[] argTypes = getParameterTypes(args);
            Constructor<?> constructor = clazz.getDeclaredConstructor(argTypes);
            constructor.setAccessible(true);
            return constructor.newInstance(args);
        }
    }

    /**
     * 获取方法对象
     */
    public Method getMethod(String className, String methodName, Class<?>... parameterTypes) throws Exception {
        Class<?> clazz = loadClass(className);
        return clazz.getMethod(methodName, parameterTypes);
    }

    /**
     * 调用方法(自动判断是否是静态方法),是否能获取到静态方法,未实测,还是能自动切换到invokeStaticMethod?
     */
    public Object invokeMethod(String className, String methodName, Object instance, Object... args) throws Exception {
        Class<?>[] argTypes = getParameterTypes(args);
        Method method = getMethod(className, methodName, argTypes);
        method.setAccessible(true);
        return method.invoke(instance, args);
    }

    /**
     * 调用静态方法
     */
    public Object invokeStaticMethod(String className, String methodName, Object... args) throws Exception {
        return invokeMethod(className, methodName, null, args);
    }

    /**
     * 辅助方法:从参数数组中推断参数类型
     */
    private Class<?>[] getParameterTypes(Object... args) {
        if (args == null || args.length == 0) {
            return new Class[0];
        }
        Class<?>[] types = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            types[i] = args[i].getClass();
        }
        return types;
    }

    // 可选:添加缓存机制(例如 Map<String, Class<?>>)提升性能
}
正文到此结束
本文目录