手动调用指定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<String, ReferenceBean<?>> referenceConfigs = (ConcurrentMap<String, ReferenceBean<?>>) 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.youkuaiyun.com/lkforce/article/details/82693626

 

本文结束

 

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

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

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

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

### 解决方案分析 在 Dubbo 3.2.4 版本中,当与 Spring Cloud 集成时遇到 `org.apache.dubbo.registry.RegistryFactory` 扩展名错误,通常是因为注册中心的相关配置未正确加载或缺少必要的依赖项。以下是详细的排查和解决方案。 #### 1. **确认依赖项** 确保项目中的 Maven 或 Gradle 文件已正确引入所需的依赖项。对于 DubboNacos 的集成,需包含以下依赖: ```xml <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>3.2.4</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId> <version>${nacos.version}</version> </dependency> ``` 上述依赖项用于支持 DubboNacos 注册中心的功能[^4]。 #### 2. **检查配置文件** 验证 `application.properties` 或 `application.yml` 中的配置是否正确设置。以下是推荐的配置示例: ##### application.properties 示例: ```properties dubbo.application.name=${spring.application.name} dubbo.protocol.name=dubbo dubbo.registry.address=nacos://localhost:8848 dubbo.registry.parameters.namespace=default dubbo.registry.parameters.group=dubbo dubbo.registry.use-as-metadata-center=false dubbo.registry.use-as-config-center=false ``` 如果使用 YAML 格式,则可以写为: ##### application.yml 示例: ```yaml dubbo: application: name: ${spring.application.name} protocol: name: dubbo registry: address: nacos://localhost:8848 parameters: namespace: default group: dubbo use-as-metadata-center: false use-as-config-center: false ``` 以上配置基于引用的内容进行了调整,确保参数名称和值匹配实际需求[^1]。 #### 3. **启用自动配置功能** Dubbo-Spring-Boot-Starter 支持通过 `@EnableAutoConfiguration` 实现自动化配置。因此,在主类上应添加如下注解: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 此部分由 Dubbo 官方文档指导完成。 #### 4. **调试扩展点问题** 如果仍然存在 `RegistryFactory` 扩展找不到的问题,可能涉及 SPI 加载机制异常。可以通过以下方式进一步诊断: - 确认 `META-INF/dubbo` 下是否存在对应的扩展实现文件。 - 如果手动指定扩展实现,可通过代码动态注入 RegistryFactory 实例: ```java import org.apache.dubbo.config.ReferenceConfig; import org.apache.dubbo.rpc.service.GenericService; ReferenceConfig<GenericService> reference = new ReferenceConfig<>(); reference.setInterface("your.interface.name"); reference.setVersion("1.0.0"); // 初始化并获取代理对象 GenericService genericService = reference.get(); Object result = genericService.$invoke("methodName", new String[]{"argType"}, new Object[]{args}); ``` 该方法适用于更复杂的场景下强制调用服务实例[^3]。 #### 5. **日志级别调整** 为了更好地定位问题,建议提高 Dubbo 日志输出等级至 DEBUG 水平。可以在 `logback.xml` 或其他日志框架配置中加入以下内容: ```xml <logger name="org.apache.dubbo" level="DEBUG"/> ``` 这有助于捕获更多上下文信息以便于后续分析。 --- ### 总结 综上所述,解决 `org.apache.dubbo.registry.RegistryFactory` 错误的关键在于校验依赖完整性、核对配置准确性以及合理运用 SPI 调试手段。按照上述步骤逐一排查即可有效解决问题。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值