手动调用指定Dubbo接口(二)----Reference篇

我写了个方法,可以给方法传递指定的Dubbo接口名,方法名,参数值,方法来调用我们指定的Dubbo接口,并返回结果。

 

在SpringBoot中使用@Reference注解标识的Dubbo接口,比如:

@Reference
OrderService orderService;

这种接口的动态代理没有被放到Spring的上下文中,而是放在了Dubbo的处理类AnnotationBean中。

这种情况下使用

WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();

获取不到这个代理。

这种情下我们可以从Dubbo的AnnotationBean中获取动态代理对象。

下面是一个调用单参数接口的例子:

@Controller
@RequestMapping("/test")
public class TestController {

    @Autowired
    WebApplicationContext webApplicationContext;

    /**
     * @param interfaceName Dubbo接口名
     * @param methodName    方法名
     * @param parameter     参数值
     * @return
     */
    @RequestMapping(value = "/test1", method = RequestMethod.POST)
    @ResponseBody
    public Object test1(@RequestParam(value = "interfaceName") String interfaceName,
                        @RequestParam(value = "methodName") String methodName,
                        @RequestParam(value = "parameter") String parameter) {
        Object result = null;
        AnnotationBean annotationBean = (AnnotationBean) webApplicationContext.getBean("annotationBean");
        try {
            Field handlerField = annotationBean.getClass().getDeclaredField("referenceConfigs");
            handlerField.setAccessible(true);
            ConcurrentMap> referenceConfigs = (ConcurrentMap>) handlerField.get(annotationBean);
            for (String key : referenceConfigs.keySet()) {
                if (key.contains(interfaceName)) {
                    ReferenceBean referenceBean = referenceConfigs.get(key);
                    Object refer = referenceBean.get();
                    Class interfaceClass = referenceBean.getInterfaceClass();
                    Method[] methodArr = interfaceClass.getMethods();
                    for (int i = 0; i < methodArr.length; i++) {
                        Method m = methodArr[i];
                        if (m.getName().equals(methodName)
                                && m.getGenericParameterTypes().length == 1) { // 命中方法,只校验了名字和参数数量
                            result = m.invoke(refer, new Object[]{parameter});
                        }
                    }
                }
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        return result;
    }

}

通过以上代码,我们可以这么传参数:

interfaceName:OrderService,或者com.test.OrderService。这是我们要调的接口名。

methodName:selectByCode。这是我们要调的接口名,假设OrderService中有selectByCode(String code)方法。

parameter:ABC123。这是我们要给方法传的参数。

 

注:

1,用@Autowired注解的WebApplicationContext是SpringBoot上下文的工具类。

2,annotationBean是Annotation在Spring上下文中注册的名字。

3,referenceConfigs是在Annotation中维护的一个Map,它的key是接口名,是这种格式的:

/com.test.OrderService:

前面有斜杠,后面有冒号。它的value则是ReferenceBean,是Dubbo接口动态代理的封装类。

4,ReferenceBean中的refer属性就是Dubbo生成的动态代理对象,可以通过referenceBean.get()方法来获得。

5,ReferenceBean中还记载了接口类的class,从而获得对应的Method。当我们有了Method,有了动态代理对象,有参数列表,就可以调用接口了。

6,上面的例子在匹配Method时,匹配的是单一字符串参数的接口,如果要匹配更多的参数模式,可以参考:

https://blog.csdn.net/lkforce/article/details/82693626

 

本文结束

 

三篇手动调用指定Dubbo接口的文章:

手动调用指定Dubbo接口(一)----Spring注入篇

手动调用指定Dubbo接口(二)----Reference篇

手动调用指定Dubbo接口(三)—GenericService篇

你可能感兴趣的:(框架,Java)