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

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;

    }
}
复制代码

反射目标调用的方法:

 

 

posted @   雨后观山色  阅读(3151)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2019-04-07 Navicat使用笔记02---Navicat 连接腾讯云
点击右上角即可分享
微信分享提示