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;

    }
}

反射目標調用的方法:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM