【Java】利用反射执行Spring容器Bean指定的方法,支持多种参数自动调用

目录

Linux系统管理——Linux安装

使用情景

  1. 将准时义务录入数据库(这样做的利益是准时义务可视化,也可以动态修改各个义务的执行时间),通过反射执行对应的方式;
  2. 配合Netty实现简朴的HTTP请求处置框架
  3. 其他需要使用反射执行Spring方式的营业亦可

目的

      许多文章都提到了反射,然则对于方式参数处置这一块都是明确了类型,不支持根据现实参数动态转换,而本篇文章提供了一个思绪怎么做到方式参数的动态挪用。
      人人也可以通过行使本文的方式连系自己的营业场景写出复用性更高、可扩展性更好的代码。迎接列位指出文章中的错误,如果有更好的思绪可以在下方谈论,我们一起讨论。
      迎接转发,请注明出处。

实现方式

条件:

明确清晰需要执行的类和方式。

思绪

  1. 通过Spring容器获取需要执行的类,注重:从spring容器中获取的类可能是被JDK或CGLIB署理的(取决于你的环境设置);
  2. 获取执行的Mehod工具;
  3. 封装方式现实参数List,仅支持基本类型包装类, String,工具,Map等参数类型自动转换
  4. 执行Mehod的invoke方式

焦点类

@Service
public class ReflectionService {

    @Resource
    private ApplicationContext applicationContext;

    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, BigDecimal.class, String.class);


    /**
     * 反射挪用spring bean方式的入口
     * @param classz 类名
     * @param methodName 方式名
     * @param paramMap 现实参数
     * @throws Exception
     */
    public void invokeService(String classz, String methodName, Map<String,Object> paramMap) throws Exception {
        if(!applicationContext.containsBean(classz)) {
            throw new RuntimeException("Spring找不到对应的Bean");
        }

        // 从Spring中获取署理工具(可能被JDK或者CGLIB署理)
        Object proxyObject = applicationContext.getBean(classz);

        // 获取署理工具执行的方式
        Method method = getMethod(proxyObject.getClass(), methodName);

        // 获取署理工具中的目的工具
        Class target = AopUtils.getTargetClass(proxyObject);

        // 获取目的工具的方式,为什么获取目的工具的方式:只有目的工具才气通过 DefaultParameterNameDiscoverer 获取参数的方式名,署理工具由于可能被JDK或CGLIB署理导致获取不到参数名
        Method targetMethod = getMethod(target, methodName);

        if(method == null) {
            throw new RuntimeException(String.format("没有找到%s方式", methodName));
        }

        // 获取方式执行的参数
        List<Object> objects = getMethodParamList(targetMethod, paramMap);

        // 执行方式
        method.invoke(proxyObject, objects.toArray());
    }

    /**
     * 获取方式现实参数,不支持基本类型
     * @param method
     * @param paramMap
     * @return
     */
    private List<Object> getMethodParamList(Method method, Map<String, Object> paramMap) throws Exception {
        List<Object> objectList = new ArrayList<>();

        // 行使Spring提供的类获取方式形参名
        DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
        String[] param =  nameDiscoverer.getParameterNames(method);

        for (int i = 0; i < method.getParameterTypes().length; i++) {
            Class<?> parameterType = method.getParameterTypes()[i];

            Object object = null;
            // 基本类型不支持,支持包装类
            if(WRAP_CLASS.contains(parameterType)) {
                if(param != null && paramMap.containsKey(param[i])){
                    object = paramMap.get(param[i]);

                    object = ConvertUtils.convert(object, parameterType);
                }

            }else if (!parameterType.isPrimitive() ) {
                object = getInstance(parameterType);

                // 赋值
                BeanUtils.populate(object, paramMap);
            }

            objectList.add(object);
        }

        return objectList;
    }

    /**
     * 获取类型实例
     * @param parameterType
     * @return
     * @throws Exception
     */
    private Object getInstance(Class<?> parameterType) throws Exception {
        if(parameterType.isAssignableFrom(List.class)) {
            return  new ArrayList();

        }else if(parameterType.isAssignableFrom(Map.class)) {
            return new HashMap();
        }else if(parameterType.isAssignableFrom(Set.class)) {
            return  new HashSet();
        }
        return parameterType.newInstance();
    }

    /**
     * 获取目的方式
     * @param proxyObject
     * @param methodStr
     * @return
     */
    private Method getMethod(Class proxyObject, String methodStr) {
        Method[] methods = proxyObject.getMethods();

        for(Method method : methods) {
            if(method.getName().equalsIgnoreCase(methodStr)) {
                return method;
            }
        }

        return null;
    }
}

测试方式

package com.ywqonly.springtest.reflection;

import com.ywqonly.springtest.reflection.service.impl.ReflectionService;
import com.ywqonly.springtest.reflection.vo.CarVO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringReflectionTest {

    @Resource
    private ReflectionService reflectionService;

    @Test
    public void paramTest() throws Exception {
        Map<String, Object>  paramMap = new HashMap<>();

        paramMap.put("carName", "宝马");
        paramMap.put("speed", "1");
        reflectionService.invokeService("carServiceImpl", "start", paramMap);
    }

    @Test
    public void objectTest() throws Exception {
        Map<String, Object>  paramMap = new HashMap<>();

        paramMap.put("carName", "宝马");
        paramMap.put("speed", "2");
        reflectionService.invokeService("carServiceImpl", "startByVO", paramMap);
    }

    @Test
    public void mapTest() throws Exception {
        Map<String, Object>  paramMap = new HashMap<>();

        paramMap.put("carName", "宝马");
        paramMap.put("speed", "3");
        reflectionService.invokeService("carServiceImpl", "startByMap", paramMap);
    }

}

源码分享

GITHUB源码地址

原创文章,作者:28x29新闻网,如若转载,请注明出处:https://www.28x29.com/archives/15557.html