springboot动态加载接口、根据字符串生成Class对象

  1. 利用Groovy脚本将字符串文本转换成Class对象
  2. 获取Class对象中的方法
  3. 组装mvc请求映射信息RequestMappingInfo
  4. 动态将接口注入spring中

第一步:利用Groovy脚本将字符串文本转换成Class对象

利用Groovy脚本动态生成对象

1.引入Groovy maven依赖 


    org.codehaus.groovy
    groovy-all
    2.4.7

2.测试代码 

import groovy.lang.GroovyClassLoader;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

public class TestGroovy {
    public static void main(String[] args) throws Exception {
        //groovy提供了一种将字符串文本代码直接转换成Java Class对象的功能
        GroovyClassLoader groovyClassLoader = new GroovyClassLoader();

        Class clazz = groovyClassLoader.parseClass("package com;\n" +
                "\n" +
                "public class Hello {\n" +
                "    \n" +
                "    public void sayHello(){\n" +
                "        System.out.println(\"hello\");\n" +
                "    }\n" +
                "}");

        // 创建对象
        Object obj = clazz.newInstance();
        // 获取方法
        Method method = clazz.getDeclaredMethod("sayHello");
        // 调用方法
        method.invoke(obj);
    }
}

执行结果为: 

hello

Process finished with exit code 0

第二步: 获取Class对象中的方法

使用Spring针对反射提供的工具类:ReflectionUtils

在类型clazz上,查询name方法,参数类型列表为paramTypes;

Method findMethod(Class clazz, String name, Class… paramTypes) 

示例代码:

import groovy.lang.GroovyClassLoader;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

public class TestReflectionUtils {
    public static void main(String[] args) throws Exception {
        //groovy提供了一种将字符串文本代码直接转换成Java Class对象的功能
        GroovyClassLoader groovyClassLoader = new GroovyClassLoader();

        Class clazz = groovyClassLoader.parseClass("package com;\n" +
                "\n" +
                "public class Hello {\n" +
                "\n" +
                "    public void sayHello(){\n" +
                "        System.out.println(\"无参方法\");\n" +
                "    }\n" +
                "\n" +
                "    public void sayHello(String name){\n" +
                "        System.out.println(\"含参数方法:\" + name);\n" +
                "    }\n" +
                "}");

        // 创建对象
        Object obj = clazz.newInstance();
        // 无参方法
        Method method = ReflectionUtils.findMethod(clazz, "sayHello");
        // 含参方法
        Method paramMethod = ReflectionUtils.findMethod(clazz, "sayHello", String.class);
        // 调用方法
        ReflectionUtils.invokeMethod(method,obj);
        ReflectionUtils.invokeMethod(paramMethod,obj,"world");
    }
}

执行结果为:

无参方法
含参数方法:world

Process finished with exit code 0

第三步: 创建mvc请求映射信息RequestMappingInfo

RequestMappingInfo的主要作用就是用来对应封装一个控制方法的@RequestMapping注解信息,该注解信息是综合了控制器方法以及控制器类上的@RequestMapping等注解属性而合成的一个信息对象

主要包含以下条件:

1.PatternsRequestCondition 请求属性
2.RequestMethodsRequestCondition 请求方法
3.ParamsRequestCondition ”参数“条件
4.HeadersRequestCondition ”headers“条件
5.ConsumesRequestCondition 请求内容
6.ProducesRequestCondition 应答内容

主要使用 PatternsRequestCondition和RequestMethodsRequestCondition,使用全参构造创建对象:

// 请求路径
PatternsRequestCondition patterns = new PatternsRequestCondition("test/api");
// 请求方法
RequestMethodsRequestCondition method = new RequestMethodsRequestCondition(RequestMethod.GET);
// 创建mvc请求映射信息
RequestMappingInfo requestMappingInfo = new RequestMappingInfo(patterns, method, null,
                null, null, null, null);

 第四步:动态将接口注入spring中

RequestMappingHandlerMapping 实现了接口InitializingBean,在bean加载完成后会自动调用afterPropertiesSet方法,在此方法中调用了initHandlerMethods()来实现初始化,

处理逻辑大致是使用RequestMappingInfo信息,注册到MappingRegistry中

RequestMappingHandlerMapping:

发布接口:registerMapping(RequestMappingInfo mapping, Object handler, Method method)

requestMappingHandlerMapping.registerMapping(requestMappingInfo, clazz.newInstance(), method);

下线接口:unregisterMapping(T mapping) 

requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);

示例代码:

import groovy.lang.GroovyClassLoader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;

@Component
public class TestMappingRegistry {

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    public void mappingRegistry() throws Exception {
        //groovy提供了一种将字符串文本代码直接转换成Java Class对象的功能
        GroovyClassLoader groovyClassLoader = new GroovyClassLoader();

        Class clazz = groovyClassLoader.parseClass("package com;\n" +
                "\n" +
                "import org.apache.ibatis.annotations.Param;\n" +
                "import org.springframework.stereotype.Controller;\n" +
                "import org.springframework.web.bind.annotation.RequestParam;\n" +
                "import org.springframework.web.bind.annotation.ResponseBody;\n" +
                "\n" +
                "@Controller\n" +
                "public class Hello {\n" +
                "\n" +
                "    public String sayHello(){\n" +
                "        return \"hello\";\n" +
                "    }\n" +
                "\n" +
                "    @ResponseBody\n" +
                "    public String sayHello(@RequestParam(\"msg\") String msg){\n" +
                "        return \"hello \" + msg;\n" +
                "    }\n" +
                "}");

        // 无参方法
        Method method = ReflectionUtils.findMethod(clazz, "sayHello");
        // 含参方法
        Method paramMethod = ReflectionUtils.findMethod(clazz, "sayHello", String.class);

        // 请求路径
        PatternsRequestCondition patterns = new PatternsRequestCondition("/test/api");
        // 请求方法
        RequestMethodsRequestCondition requestMethod = new RequestMethodsRequestCondition(RequestMethod.GET);
        // 创建mvc请求映射信息
        RequestMappingInfo requestMappingInfo = new RequestMappingInfo(patterns, requestMethod, null,
                null, null, null, null);
        // 发布接口(含参方法)
        requestMappingHandlerMapping.registerMapping(requestMappingInfo, clazz.newInstance(), paramMethod);
    }
}

调用 "/test/api" 接口:

springboot动态加载接口、根据字符串生成Class对象_第1张图片

 

 至此动态接口发布成功!

注意事项:发布的接口不受spring管理,无法使用切面、@Autowired注解等!!!

你可能感兴趣的:(spring,boot)