美文网首页
日拱一卒:Java 反射之动态方法调用2

日拱一卒:Java 反射之动态方法调用2

作者: Tinyspot | 来源:发表于2023-11-16 11:10 被阅读0次

1. 入口类 DynamicExecuteController

@RestController
@RequestMapping("/dynamic")
public class DynamicExecuteController {

    @Resource
    private DynamicExecuteService dynamicExecuteService;

    /**
     * service: com.example.concrete.starter.service.GreetService
     * method: com.example.concrete.starter.service.GreetService.greet()
     * args: ["xing","Local"]
     *
     * @param param
     * @return
     */
    @RequestMapping("/execute")
    public Object execute(String param) {
        if ("greet".equals(param)) {
            param = "{\"service\": \"com.example.concrete.starter.service.GreetService\",\n" +
                    "    \"method\": \"public abstract java.lang.String com.example.concrete.starter.service.GreetService.greet()\"}";
        } else if ("greet2".equals(param)){
            param = "{\"service\": \"com.example.concrete.starter.service.GreetService\",\n" +
                    "    \"method\": \"public abstract java.lang.String com.example.concrete.starter.service.GreetService.greet(java.lang.String)\",\n" +
                    "    \"args\": [\n" +
                    "        \"Tinyspot\"\n" +
                    "    ]}";
        } else if ("greet3".equals(param)) {
            param = "{\"service\": \"com.example.concrete.starter.service.GreetService\",\n" +
                    "    \"method\": \"public abstract java.lang.String com.example.concrete.starter.service.GreetService.greet(java.lang.String,java.lang.String)\",\n" +
                    "    \"args\": [\"Alice\", \"Tinyspot\"]}";
        } else if ("greet4".equals(param)) {
            // 参数值组装
            // List<String> list = Arrays.asList(JSON.toJSONString(new UserDTO("xing", 20)), "Local");
            // System.out.println(JSON.toJSONString(list.toArray()));
            param = "{\"service\": \"com.example.concrete.starter.service.GreetService\",\n" +
                    "    \"method\": \"public abstract java.lang.String com.example.concrete.starter.service.GreetService.greeting(com.example.concrete.common.domain.UserDTO,java.lang.String)\",\n" +
                    "    \"args\": [\"{\\\"age\\\":20,\\\"name\\\":\\\"Tinyspot\\\"}\",\"Local\"]}";
        }

        return dynamicExecuteService.execute(param);
    }
}

请求URL http://localhost:8080/dynamic/execute?param=greet4

2. 业务类

@Description("工具测试")
public interface GreetService {

    @Description("打招呼4")
    String greeting(UserDTO userDTO, @Description("当前环境") String env);

    @Description("打招呼")
    String greet();

    @Description("打招呼1")
    String greet(Integer value);

    @Description("打招呼2")
    String greet(String name);

    @Description("打招呼3")
    String greet(String name, String myName);
}
@Service
public class GreetServiceImpl implements GreetService {

    @Override
    public String greeting(UserDTO userDTO, String env) {
        return "greeting:" + userDTO.toString() + "; env=" + env;
    }

    @Override
    public String greet(Integer value) {
        return "Integer:" + value;
    }

    @Override
    public String greet() {
        return "greet...";
    }

    @Override
    public String greet(String name) {
        return "Hello " + name;
    }

    @Override
    public String greet(String name, String myName) {
        return "Hello " + name + ", my name is " + myName;
    }
}

注解 @Description

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Description {

    String value();

    String remark() default "";

}

UserDTO 类

@Data
public class UserDTO  extends BaseDTO {
    private static final long serialVersionUID = 5196056007908280999L;

    private String name;
    private Integer age;
    private Integer status;
    private Long total;
    private Boolean isOwner;

    public UserDTO() {
    }

    public UserDTO(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.io.Serializable;

public class BaseDTO implements Serializable {
    private static final long serialVersionUID = 1208436728115984191L;

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}

3. 解析

@Service
public class DynamicExecuteService {

    @Resource
    protected ApplicationContext applicationContext;

    public Object execute(String param) {
        Object result = null;
        try {
            final Request request = JSON.parseObject(param, Request.class);

            Class<?> clazz = Class.forName(request.getService());
            Object service = this.applicationContext.getBean(clazz);

            ServiceDescription serviceDescription = ServiceDescription.buildServiceDescription(clazz);
            MethodDescription method = serviceDescription.findMethod(request.getMethod());

            result = DescriptionUtil.execute(service, method, request.getArgs());
        } catch (Throwable e) {
            Map<String, String> errorMap = new HashMap<>();
            errorMap.put("errorMessage", e.getMessage());
            errorMap.put("stackTrace", ExceptionUtils.getStackTrace(e));
            return errorMap;
        }
        return result;
    }

    @Data
    public static class Request {
        private String service;
        private String method;
        private List<String> args = new ArrayList<>();
    }
}
public class DescriptionUtil {

    public static Object execute(Object service, MethodDescription method, List<String> arguments) throws InvocationTargetException, IllegalAccessException {
        if (method.getParameters().size() != arguments.size()) {
            return "参数不对";
        }

        List<Object> args = new ArrayList<>();
        for (int i = 0; i < arguments.size(); i++) {
            args.add(getArgValue(method.getParameters().get(i).getParameterClazz(), arguments.get(i)));
        }

        return method.getMethod().invoke(service, args.toArray());
    }

    private static Object getArgValue(Class<?> parameterType, String arg) {
        if (arg == null) {
            return null;
        }

        arg = StringUtils.trim(arg);

        if (parameterType.equals(String.class)) {
            return arg;
        }

        if (parameterType.equals(Date.class)) {
            if (arg.length() == 10) {
                // 日期补全
                arg += " 00:00:00";
            }

            return DateUtil.parseToDateTime(arg);
        }

        if (StringUtils.isBlank(arg)) {
            return null;
        }

        return JSON.parseObject(arg, parameterType);
    }
}

4. 模型

public class ServiceDescription {

    private Description description;
    private Class<?> serviceClazz;
    private List<MethodDescription> methods = new ArrayList<>();

    public Description getDescription() {
        return description;
    }

    public void setDescription(Description description) {
        this.description = description;
    }

    public Class<?> getServiceClazz() {
        return serviceClazz;
    }

    public void setServiceClazz(Class<?> serviceClazz) {
        this.serviceClazz = serviceClazz;
    }

    public List<MethodDescription> getMethods() {
        return methods;
    }

    public MethodDescription findMethod(final String methodSign) {
        return getMethods().stream()
                .filter(methodDescription -> methodDescription.getMethodSign().equals(methodSign))
                .findFirst()
                .orElse(null);
    }

    public static ServiceDescription buildServiceDescription(Class<?> clazz) {
        if (clazz == null) {
            return null;
        }

        Description description = clazz.getAnnotation(Description.class);
        if (description == null) {
            return null;
        }

        ServiceDescription serviceDescription = new ServiceDescription();
        serviceDescription.setDescription(description);
        serviceDescription.setServiceClazz(clazz);
        fillMethods(serviceDescription, clazz);

        return serviceDescription;
    }

    private static void fillMethods(ServiceDescription serviceDescription, Class<?> clazz) {
        for (Method method : clazz.getDeclaredMethods()) {
            Description description = method.getAnnotation(Description.class);
            if (description == null) {
                continue;
            }

            MethodDescription methodDescription = new MethodDescription();
            methodDescription.setDescription(description);
            methodDescription.setMethod(method);
            fillParameters(methodDescription, method);

            serviceDescription.getMethods().add(methodDescription);
        }
    }

    private static void fillParameters(MethodDescription methodDescription, Method method) {
        for (int i = 0; i < method.getParameterTypes().length; i++) {
            ParameterDescription parameterDescription = new ParameterDescription();
            parameterDescription.setDescription(getDescriptions(method, i));
            parameterDescription.setParameterClazz(method.getParameterTypes()[i]);

            methodDescription.getParameters().add(parameterDescription);
        }
    }

    private static Description getDescriptions(Method method, int paramIndex) {
        Annotation[] annotations = method.getParameterAnnotations()[paramIndex];

        for (Annotation annotation : annotations) {
            if (annotation instanceof Description) {
                return (Description) annotation;
            }
        }

        return null;
    }

}
@Data
public class MethodDescription {
    private Description description;
    private Method method;
    private List<ParameterDescription> parameters = new ArrayList<>();

    public String getMethodSign() {
        return this.method.toString();
    }
}
@Data
public class ParameterDescription {
    private Description description;
    private Class<?> parameterClazz;
}

相关文章

  • Java动态代理

    java动态代理 先看Method反射,调用getDeclaredMethod查找方法;invoke执行方法,返回...

  • Java反射与动态代理

    Java反射 Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制 特点:...

  • java反射机制

    java反射机制是为了动态获取类的结构,动态地调用对象的方法 java反射机制 获取类Class对象 A.clas...

  • Java基础之反射

    Java基础之反射 反射基本介绍 反射的使用通过反射调用属性和方法通过反射获取配置文件 反射基本介绍 Java反射...

  • Java系列之 - 反射基础

    java反射 反射:动态获取类的信息,以及动态调用对象的方法的功能。可以理解为动态看透类的能力。 主要功能: 在运...

  • 【日拱一卒】:反射的作用和意义?

    Java的反射:在程序运行过程中,动态的获取类的信息和动态调用对象的方法。反射就是把java类中的各种成分映射成一...

  • Java 反射

    Java反射Java反射API获取Class对象通过反射创建实例对象,调用公共方法通过反射调用私有方法 一.Jav...

  • java 泛型基础(详细例子)

    Java基础之一反射 动态加载类的方法 editPlus配合cmd命令行调用 file-new-java,保存Ja...

  • java反射invoke动态调用方法

    @Autowired标签自动注入TestMapper失败,可能出现的空指针报错: java.lang.NullPo...

  • 有疑问的地方

    反射和动态代理:java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模...

网友评论

      本文标题:日拱一卒:Java 反射之动态方法调用2

      本文链接:https://www.haomeiwen.com/subject/fmiewdtx.html