dubbo refrence bean (service reference)

Keywords: Java Dubbo Spring xml Attribute

Write a dubbo tag on xml to refer remote services to local use:

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

Since spring is Schema, dubbo has custom Schema, in dubbo Namespace Handler:

registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
spring inherits BeanDefinition Parser to implement custom rules for parsing xml. Parsing is implemented in DubboBean Definition Parser.
Eventually, a BeanDefinition corresponding to the class is generated. BeanDefinition is the data source for bean s in spring.
Each tag corresponds to the 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 tag property document: http://dubbo.io/user-guide/reference-xmlconf/dubbo-reference.html
 
The inheritance structure of ReferenceBean:
Looking directly at the afterPropertiesSet() method, this method is executed after the bean is initialized in spring. Each component is injected into the method:
ConsumerConfig, Application Config, List < Registry Config >, MonitorConfig, ModuleConfig, and then this code:
        Boolean b = isInit();
        if (b == null && getConsumer() != null) {
            b = getConsumer().isInit();
        }
        if (b != null && b.booleanValue()) {
            getObject();
        }

This init is an optional property when the reference tag was set earlier. If we set true, the getObject() method will be executed when the afterPropertiesSet() is executed.

  public Object getObject() throws Exception {
        return get();
    }
This getObject is the implementation of FactoryBean. In spring container, FactoryBean is different from ordinary beans. It is not the instance of the FactoryBean that is obtained directly by the getBean method of the BeanFactory class, but the object returned by the method getObject in the FactoryBean. So when we execute BuyFoodService buyFoodService = context. getBean ("buyFoodService");
This code will also execute to the getObject() method.
The getObject() method calls the get() of the parent ReferenceConfig class; then the init() method is called.
 public synchronized T get() {
        if (destroyed) {
            throw new IllegalStateException("Already destroyed!");
        }
        if (ref == null) {
            init();
        }
        return ref;
    }
Look at this init method. It's not very well written. It's like plaster scattered all over the place. Regardless, look directly at the code it returns:
invoker = refprotocol.refer(interfaceClass, url);
// Creating Service Agents
return (T) proxyFactory.getProxy(invoker);
First, protcolc shovels up an invoker, and then the invoker agent is used.
This proxyFactory and Proocol we see are obtained as follows:
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
ProxyFactory code:
@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 code:
@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 is implemented by default with javassist and Protocol by default with dubbo, so let's focus on two subclasses: JavassistProxyFactory and DubboProtocol.
 
1. The refer method of DubboProtocol returns a DubboInvoker.
2. JavassistProxyFactory generates a proxy class dynamically using DubboInvoker as a proxy object
 
The Invoker is generated in turn by ProtocolListener Wrapper, ProtocolFilter Wrapper, Registry Protocol, Dubbo Protocol.
In this process, you need to assemble instances that store the necessary information for service invocation, like the information in the registry. Many of these details, follow-up study.
 
So ProxyFactory is Javassist ProxyFactory, which was first implemented by StubProxyFactory Wrapper, as mentioned in the previous article. The constructor parameter of StubProxyFactoryWrapper is ProxyFactory, which was described in the previous article. Implementation of Listener in dubbo It's also involved. He did the logic in getProxy.
First understand Stub (stub). Calling a service remotely in dubbo is encapsulated as a local service. Usually we refer to the interface and can call its method. The implementation is in remote application. But we want to do something before making a remote request, such as doing ThreadLocal cache, validating parameters in advance, forging fault-tolerant data after the call fails. That's what stub does. This logic is in StubProxyFactoryWrapper's getProxy method. Let's look at its code:
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
    T proxy = proxyFactory.getProxy(invoker);
    if (GenericService.class != invoker.getInterface()) {
       // Check to see if there is any stub attribute
        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 {
                    // Judging whether there is a parameter is Ben service Constructor, which is required to be available
                    Constructor<?> constructor = ReflectUtils.findConstructor(stubClass, serviceType);
                    // Seen here is direct use constructor,No judgment, not very good, if there is no constructor to throw exceptions to print out friendly prompts may be better. Here it is. JavassistProxyFactory Well formed proxy A decoration example is generated as a parameter. So here it is stub The methods implemented in the class can perform operations such as capturing exceptional parameter checking.
                    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;
}

 

Returns the proxy instance, so the BuyFoodService declared at the beginning actually points to a wrapped proxy in the spring container.

 

Posted by smalband on Fri, 24 May 2019 15:17:54 -0700