美文网首页
日拱一卒: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 反射之动态方法调用2

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