dubbo中关于@reference注解无法配置MethodConfig的解决方法

本文针对目前为止最新的dubbo版本2.6.2中存在的问题,ReferenceConfig中有一个List<MethodConfig> methods属性,但是@Reference注解里面并没有可以配置这个属性的地方(听dubbo的committer说下个版本会修复),以前写过一篇设置timeout属性的文章,可以通过parameters曲线救国,但是有些属性是不管用的,比如本次要说的onreturn、onthrow、oninvoke三个methodConfig的属性,就不能通过parameters参数传入生效。

 通过对源码进行debug之后,发现目前只有一个地方可以植入代码实现这个功能,就是修改:

com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder

这个类的源码,在ReferenceBean实例化之后,ReferenceConfig.init方法调用之前置入这个methods属性,并没有什么扩展点,只能修改源代码来实现:

修改com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#postConfigureBean方法:

    @Override
    protected void postConfigureBean(Reference annotation, ReferenceBean bean) throws Exception {

        bean.setApplicationContext(applicationContext);

        configureInterface(annotation, bean);

        configureConsumerConfig(annotation, bean);
        //配置ReferenceBean的methods属性
        configureMethodConfig(annotation, bean);

        bean.afterPropertiesSet();

    }

增加一个configureMethodConfig方法:

private void configureMethodConfig(Reference reference, ReferenceBean bean) {
        List<MethodConfig> methods = new ArrayList<>();
        Wrapper interfaceWrapper = Wrapper.getWrapper(bean.getInterfaceClass());
        Map<String, String> parameters = bean.getParameters();
        for (Map.Entry<String, String> entry : parameters.entrySet()) {
            if (entry.getKey().endsWith("onreturn") || entry.getKey().endsWith("onthrow") || entry.getKey().endsWith("oninvoke")) {
                int index = entry.getKey().lastIndexOf(".");
                String interfaceMethod = entry.getKey().substring(0, index);
                String callbackMethod = entry.getKey().substring(index + 1);
                if (interfaceWrapper.hasMethod(interfaceMethod)) {
                    int refIndex = entry.getValue().lastIndexOf(".");
                    String ref = entry.getValue().substring(0, refIndex);
                    String refMethod = entry.getValue().substring(refIndex + 1);
                    Object refBean = applicationContext.getBean(ref);
                    MethodConfig methodConfig = new MethodConfig();
                    methods.add(methodConfig);
                    methodConfig.setName(interfaceMethod);
                    try {
                        BeanInfo beanInfo = Introspector.getBeanInfo(methodConfig.getClass());
                        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

                        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {

                            Method writeMethod = propertyDescriptor.getWriteMethod();

                            if (propertyDescriptor.getName().equals(callbackMethod) && writeMethod != null) {
                                writeMethod.invoke(methodConfig, refBean);
                            }
                            if (propertyDescriptor.getName().equals(callbackMethod + "Method") && writeMethod != null) {
                                writeMethod.invoke(methodConfig, refMethod);
                            }

                        }
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }

                }
            }
        }


        bean.setMethods(methods);
    }

然后我们就可以在@Reference中配置parameters参数来注入methodConfig的属性(上述方法只解析了onreturn,onthrow,oninvoke三个属性值):

@RestController
public class DemoConsumerController {


    @Reference(

            version = "${demo.service.version}",
            application = "${dubbo.application.id}",
            registry = "${dubbo.registry.id}",
            retries = 1,
            parameters = {"sayHello.timeout", "3000", "sayHello2.timeout", "5000", "sayHello.onreturn", "myCallback.callback"},
            listener = "myInvokerListener"

    )
    private DemoService demoService;


    @RequestMapping("/sayHello")
    public String sayHello(@RequestParam String name) throws ExecutionException, InterruptedException {

        return demoService.sayHello(name);
    }

    @RequestMapping("/sayHello2")
    public String sayHello2(@RequestParam String name) throws ExecutionException, InterruptedException {

        return demoService.sayHello2(name);
    }
}

比如这里设置了sayHello.onreturn = myCallback.callback,指明了sayHello这个方法的onreturn属性为myCallback.callback,myCallback是bean ref名称,callback是具体要执行的回调方法,然后会生成一个MethodConfig对象,onreturn属性为 myCallback bean,onreturnMethod属性为callback。当执行sayHello方法完成之后就会调用myCallback bean实例的callback方法。

当然此处只是抛砖引玉,更对定制化的方法可以通过类似的方式自己去实现。

猜你喜欢

转载自blog.csdn.net/xiao_jun_0820/article/details/81452722