dubbo refrence bean(服务引用)

在xml上写一个dubbo标签就可以把远程的服务引用到本地使用:

<dubbo:service interface="com.test.dubbo.service.BuyFoodService" ref="buyFoodService"/>

既然用spring那就是Schema了,dubbo中自定义了Schema,在DubboNamespaceHandler中:

registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));

spring 中继承BeanDefinitionParser 实现自定义解析xml的规则。DubboBeanDefinitionParser内实现了解析。

最终要生成一个对应class的BeanDefinition。BeanDefinition在spring中时bean的数据源。

各个标签对应的pojo:

public void init() {
     registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(plicationConfig.class, true));
     registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(duleConfig.class, true));
     registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(gistryConfig.class, true));
     registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(nitorConfig.class, true));
     registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(oviderConfig.class, true));
     registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(nsumerConfig.class, true));
     registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(otocolConfig.class, true));
     registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(rviceBean.class, true));
     registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ferenceBean.class, false));
     registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(notationBean.class, true));
 } 

Reference标签的属性文档:http://dubbo.io/user-guide/reference-xmlconf/dubbo-reference.html

ReferenceBean的继承结构:

直接看afterPropertiesSet()方法,在spring中初始化好bean后会执行这个方法,方法中会注入各个组件:

ConsumerConfig,ApplicationConfig,List<RegistryConfig>,MonitorConfig,ModuleConfig,然后是这段代码:

        Boolean b = isInit();
        if (b == null && getConsumer() != null) {
            b = getConsumer().isInit();
        }
        if (b != null && b.booleanValue()) {
            getObject();
        }

这个init就是前面设置reference标签时的一个可选属性,如果我们设置true,那么在执行afterPropertiesSet()的时候就会执行到这个getObject()方法。

  public Object getObject() throws Exception {
        return get();
    }

这个getObject是FactoryBean的实现,这个在spring容器中,FactoryBean跟普通Bean不同,通过BeanFactory类的getBean方法直接获取到的并不是该FactoryBean的实例,而是该FactoryBean中方法getObject返回的对象。所以当我们执行BuyFoodService buyFoodService = (BuyFoodService) context.getBean("buyFoodService");

这样的代码是就也会执行到getObject()方法。

getObject()方法中调用的是父类ReferenceConfig的get();然后会调用到init()方法。

 public synchronized T get() {
        if (destroyed) {
            throw new IllegalStateException("Already destroyed!");
        }
        if (ref == null) {
            init();
        }
        return ref;
    }

看这个init方法,写得不怎么样,像膏药一样一块块散落着一地。先不管,直接看它返回的代码:

invoker = refprotocol.refer(interfaceClass, url);

// 创建服务代理

return (T) proxyFactory.getProxy(invoker);

首先protcolc铲射高一个invoker,然后把这个invoker代理,来提供使用。

这个proxyFactory和Protocol我们看到是这样获取的:

private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
ProxyFactory的代码:
@SPI("javassist")
public interface ProxyFactory {
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
Protocol的代码:
@SPI("dubbo")
public interface Protocol {
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
    void destroy();

}

ProxyFactory用javassist作为默认实现,Protocol默认用dubbo,所以我们先关注两个子类:JavassistProxyFactory和DubboProtocol。

1,DubboProtocol的refer方法返回一个DubboInvoker。

2,JavassistProxyFactory把DubboInvoker作为被代理对象动态产生一个代理类

在生成Invoker的时候依次执行的是:ProtocolListenerWrapper,ProtocolFilterWrapper,RegistryProtocol,DubboProtocol。

在这个过程中需要像注册中心那信息,组装出存储service调用必要信息的实例。其中很多细节,后续自己研究。

那么ProxyFactory是JavassistProxyFactory,其实先执行的是StubProxyFactoryWrapper,在前面文章提到过了这种机制。StubProxyFactoryWrapper的构造函数参数是ProxyFactory,这里在上篇dubbo中Listener的实现中也有涉及到。他在getProxy里做了逻辑。

先了解下Stub(存根),在dubbo中远程调用一个服务被封装成一个本地service,一般我们都是引用接口,就可以调用到它的方法,实现则在远程的应用上,但当我们想在发起远程请求前做一些事情,比如做ThreadLocal缓存,提前验证参数,调用失败后伪造容错数据。这个就是stub要实现的事情。这段逻辑就在StubProxyFactoryWrapper的getProxy方法里。我们来看一下它代码:

public <T> T getProxy(Invoker<T> invoker) throws RpcException {
    T proxy = proxyFactory.getProxy(invoker);
    if (GenericService.class != invoker.getInterface()) {
       // 查看有没有stub属性
        String stub = invoker.getUrl().getParameter(Constants.STUB_KEY, invoker.getUrl().getParameter(Constants.LOCAL_KEY));
        if (ConfigUtils.isNotEmpty(stub)) {
            Class<?> serviceType = invoker.getInterface();
            if (ConfigUtils.isDefault(stub)) {
                if (invoker.getUrl().hasParameter(Constants.STUB_KEY)) {
                    stub = serviceType.getName() + "Stub";
                } else {
                    stub = serviceType.getName() + "Local";
                }
            }
            try {
                Class<?> stubClass = ReflectUtils.forName(stub);
                if (! serviceType.isAssignableFrom(stubClass)) {
                    throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + serviceType.getName());
                }
                try {
                    // 判断有没有参数是本service的构造函数,要有这个函数才能可用
                    Constructor<?> constructor = ReflectUtils.findConstructor(stubClass, serviceType);
                    // 这里看到是直接使用constructor,并没有判断,不是很好,如果没有构造函数需要抛出异常打印出友好的提示可能会好点。这里就是把JavassistProxyFactory生成好的proxy作为参数生成出装饰实例。如此在这个stub类里实现的方法中可以进行比如捕获异常参数校验等操作了。
                    proxy = (T) constructor.newInstance(new Object[] {proxy});
                    //export stub service
                    URL url = invoker.getUrl();
                    if (url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT)){
                        url = url.addParameter(Constants.STUB_EVENT_METHODS_KEY, StringUtils.join(Wrapper.getWrapper(proxy.getClass()).getDeclaredMethodNames(), ","));
                        url = url.addParameter(Constants.IS_SERVER_KEY, Boolean.FALSE.toString());
                        try{
                            export(proxy, (Class)invoker.getInterface(), url);
                        }catch (Exception e) {
                            LOGGER.error("export a stub service error.", e);
                        }
                    }
                } catch (NoSuchMethodException e) {
                    throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implemention class " + stubClass.getName(), e);
                }
            } catch (Throwable t) {
                LOGGER.error("Failed to create stub implemention class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", cause: " + t.getMessage(), t);
                // ignore
            }
        }
    }
    return proxy;
}

返回代理实例,所以在开头申明的BuyFoodService,在spring容器中实际指向的是一个封装好的代理。

时间: 2024-10-08 22:12:58

dubbo refrence bean(服务引用)的相关文章

9. Dubbo原理解析-代理之服务引用

服务引用是服务的消费方向注册中心订阅服务提供方提供的服务地址后向服务提供方引用服务的过程. 服务的应用方在spring的配置实例如下: <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo. DemoService"/> 如上配置spring在容器启动的时候会解析自定义的schema元素<dubbo: reference/>转换成dubbo内部数据结构Refer

基于开源Dubbo分布式RPC服务框架的部署整合

一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目中有着广泛应用.dubbo 通过高性能 RPC 实现服务的输出和输入功能,框架基于 Spring Framework 进行无缝集成,使用过程中基本看不到 Dubbo API的直接调用,Dubbo服务支持RMI.Hessian.Dubbo.WebService等众多通信协议,同时提供了对服务的监控和管

Dubbo中暴露服务的过程解析

dubbo暴露服务有两种情况,一种是设置了延迟暴露(比如delay="5000"),另外一种是没有设置延迟暴露或者延迟设置为-1(delay="-1"): 设置了延迟暴露,dubbo在Spring实例化bean(initializeBean)的时候会对实现了InitializingBean的类进行回调,回调方法是afterPropertySet(),如果设置了延迟暴露,dubbo在这个方法中进行服务的发布. 没有设置延迟或者延迟为-1,dubbo会在Spring实例

【Rpc】基于开源Dubbo分布式RPC服务框架的部署整合

一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目中有着广泛应用.dubbo 通过高性能 RPC 实现服务的输出和输入功能,框架基于 Spring Framework 进行无缝集成,使用过程中基本看不到 Dubbo API的直接调用,Dubbo服务支持RMI.Hessian.Dubbo.WebService等众多通信协议,同时提供了对服务的监控和管

服务引用

执行步骤 ReferenceBean.getObject() -->ReferenceConfig.get() -->init() -->createProxy(map) -->refprotocol.refer(interfaceClass, urls.get(0)) -->ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("registry"); -->extensio

C# 动态修改 Web 服务引用

我们添加webService引用,一般是通过 添加服务引用完成的,其实 添加服务引用 在背后为我们生成了代理类. 我们手动生成代理类方法: 1. 编译成cs文件:TestService.cs     在vs2008命令提示窗口中输入: wsdl /out:d:\TestService.cs http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl 2.将生成的TestService.cs拷到项目中,既可以使用WebSer

Xamarin.Form 初学 之 服务引用-WCF服务引用

最近研究一下Xamarin.Form,感觉这个东西确实不错,之前一直做WPF相关,然后看到Xamarin.Form开发与WPF特别相似的语法.很有兴趣! 可是环境部署对于小白的我,可是费了不少功夫!安装VS2015费了我好些时间!安装部署以后再说!先说说引用WCF服务的坑吧! 官方文档:Xamarin可以调用WCF,可以怎么调用???(满脑子问号)https://developer.xamarin.com/guides/xamarin-forms/web-services/consuming/w

添加web引用和添加服务引用有什么区别?

添加web引用和添加服务引用有什么区别,Add Service References 和 Add Web References 有啥区别?参考 http://social.microsoft.com/Forums/zh-CN/xmlwebserviceszhchs/thread/808d870b-49f1-47ac-b105-4beb580bcec6 (1)VS2005里提供的Add Web Reference(添加Web服务引用)的功能主要是添加Web Service引用.(2)VS2008保

VS2012 添加服务引用常见错误

问题:用vs2012 添加wcf引用时在对象查看器中找不到 服务引用的类 例如默认高级配置: 解决办法:在服务的高级配置中,将重新使用引用的程序集中的类型 选项勾去掉 点击确定  即可