• Springcloud学习笔记44springboot应用中利用反射调用某个类的某个方法


    1.使用ApplicationContextAware获取spring容器中的Bean

    在spring项目中,只有都是容器中的bean才可以互取(即依赖注入),比如说userController和userService都是容器中的实例bean,所以在userController中可以注入userService。

    但是也会有一些特殊场景需求,自己不是容器中的bean,但是却要注入bean来实现调用这个bean中的方法;

    对于系统中非Spring框架管理的类,如果需要获取Spring管理的类,或者,程序中需要动态的根据Bean的id来获取Bean实例,不可能事先为该类提供所有需要的Bean属性的setter方法,在类似这样的情况下,需要获取Spring框架管理的类实例;

    package com.ttbank.flep.util;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    /**
     * @Author lucky
     * @Date 2022/4/7 19:09
     */
    @Slf4j
    @Component
    public class SpringUtil implements ApplicationContextAware {
        //上下文对象实例
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if (SpringUtil.applicationContext == null) {
                SpringUtil.applicationContext = applicationContext;
            }
        }
    
        //获取applicationContext
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        //通过name获取 Bean.
        public static Object getBean(String name) {
            return getApplicationContext().getBean(name);
        }
    
        //通过class获取Bean.
        public static <T> T getBean(Class<T> clazz) {
            return getApplicationContext().getBean(clazz);
        }
    
        //通过name,以及Clazz返回指定的Bean
        public static <T> T getBean(String name, Class<T> clazz) {
            return getApplicationContext().getBean(name, clazz);
        }
    
    }
    之所以方法类SpringUtil能够灵活自如地获取ApplicationContext,就是因为spring能够为我们自动地执行了setApplicationContext。但是,spring不会无缘无故地为某个类执行它的方法的,所以,就很有必要通过注册方法类SpringUtil的方式告知spring有这样子一个类的存在。这里我们使用@Component来进行注册;

    2.利用反射调用某个类的某个方法

    package com.ttbank.flep.controller;
    
    import com.ttbank.flep.util.SpringUtil;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Author lucky
     * @Date 2022/4/7 16:36
     */
    @RestController
    @RequestMapping("/reflectiontest")
    public class ReflectionController {
        @Autowired
        SpringUtil springUtil;
    
        @PostMapping("/getQuartzInfo")
        public void getQuartzInfo(String jobName,String jobGroupName,String className,String methodName){
            try {
    //            Class<?> clazz = Class.forName("com.ttbank.flep.controller.QuartzController");
    //            Object o = clazz.newInstance();
                //01 获取spring容器中的Bean
                className=StringUtils.uncapitalize(className); //类名首字母小写
                Object proxyObject = springUtil.getBean(className);
                //02 利用bean获取class对象,进而获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的)
                Method[] methods = proxyObject.getClass().getMethods();
                //03 获取指定的方法
                Method method1=null;
                for (Method method : methods) {
                    if(method.getName().equalsIgnoreCase(methodName)){
                        method1=method;
                        break;
                    }
                }
                //04 封装方法需要的参数
                List<Object> paramsList=new ArrayList<>();
                paramsList.add(jobName);
                paramsList.add(jobGroupName);
                method1.invoke(proxyObject,paramsList.toArray());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    postman发起请求:

    测试前:

    测试后:

     3.获取某个类的某个方法的形参变量名

    3.1 相关知识补充

    (1) ConvertUtils

    ConvertUtils 进行数据转换

            <dependency>
                <groupId>commons-beanutils</groupId>
                <artifactId>commons-beanutils</artifactId>
                <version>1.9.4</version>
            </dependency>

    ConvertUtils 是 Commons-BeanUtils 包中的一个数据类型转换工具类,主要用来在字符串和各种类型数据间进行转换,还包括对数组的转换。

    Object convert = ConvertUtils.convert("2343", Integer.class);

    3.2 使用案例

    package com.ttbank.flep.controller;
    
    import com.alibaba.fastjson.JSONObject;
    import com.sun.media.jfxmedia.logging.Logger;
    import com.ttbank.flep.entity.Param;
    import com.ttbank.flep.util.SpringUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.beanutils.ConvertUtils;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.DefaultParameterNameDiscoverer;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.*;
    
    /**
     * @Author lucky
     * @Date 2022/4/7 16:36
     */
    @Slf4j
    @RestController
    @RequestMapping("/reflectiontest")
    public class ReflectionController {
        private static final List<Class> WRAP_CLASS= Arrays.asList(Integer.class,Boolean.class,Double.class,Byte.class,Short.class,Long.class,Float.class,Double.class,String.class);
    
        @Autowired
        SpringUtil springUtil;
    
        /**
         * 根据指定的方法名获取方法;
         */
        private Method getMethod(Object proxyObject, String methodName) {
            //01 利用bean获取class对象,进而获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的)
            Method[] methods = proxyObject.getClass().getMethods();
            //02 循环遍历,获取指定方法名的方法
            for (Method method : methods) {
                if(method.getName().equalsIgnoreCase(methodName)){
                    return method;
                }
            }
            return null;
        }
    
        @PostMapping("/getMethodParamList")
        public void getMethodParamList(String className,String methodName){
            //01 获取spring容器中的Bean
            className=StringUtils.uncapitalize(className); //类名首字母小写
            Object proxyObject = springUtil.getBean(className);
            //02 利用bean获取class对象,进而获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的)
            Method method1=getMethod(proxyObject,methodName);
            //03 利用spring提供的类获取方法的形参名
            DefaultParameterNameDiscoverer nameDiscoverer=new DefaultParameterNameDiscoverer();
            String[] params = nameDiscoverer.getParameterNames(method1);
            Map<String, Object> paramMap = getParamMap();
            List<Object> paramValueList=new ArrayList<>();
            //04 遍历方法的各个形参,获取Map中的参数值;
            for (int i = 0; i <method1.getParameterTypes().length ; i++) {
                Class<?> parameterType = method1.getParameterTypes()[i];
                Object object=null;
                if(WRAP_CLASS.contains(parameterType)){
                    if(paramMap.containsKey(params[i])){
                        object=paramMap.get(params[i]);
                        object=ConvertUtils.convert(object,parameterType);
                        log.info("2222");
                    }
                }else if(!parameterType.isPrimitive()){
                    String value=(String) paramMap.get(params[i]);
                    object=JSONObject.parseObject(value,parameterType);
                    log.info("3333");
                }
                paramValueList.add(object);
            }
            log.info("OK");
            try {
                method1.invoke(proxyObject,paramValueList.toArray());
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
        public Map<String,Object> getParamMap(){
            Map<String,Object> paramMap=new HashMap<>();
            paramMap.put("location","D:\\data" );
            Param param=new Param();
            param.setSubsysCode("STPM");
            param.setContentId("10000001");
    
            String paramStr = JSONObject.toJSONString(param);
            paramMap.put("params",paramStr );
            return paramMap;
    
        }
    }

    反射目标调用的方法:

  • 相关阅读:
    理解极大似然估计(MLE)
    模型评估——ROC、KS
    tf.estimator.Estimator类的用法
    TensorFlow中数据读取之tfrecords
    常用数据库的启动与关闭
    几种常见的损失函数
    目标检测模型的性能评估--MAP(Mean Average Precision)
    正则化如何防止过拟合
    Android学习笔记之ConnectivityManager+NetWorkInfo
    关于2015年的相关总结
  • 原文地址:https://www.cnblogs.com/luckyplj/p/16114038.html
Copyright © 2020-2023  润新知