Dubbo容器--Provider

1,Dubbo服务提供者-Provider,提供RPC具体服务。一个典型的Dubbo提供者配置如下:

<dubbo :application name = "sync-data-consumer-1" />
     <dubbo :registry protocol = "zookeeper"  address = "zoo4.superboss.cc:30002,zoo5.superboss.cc:30002,zoo6.superboss.cc:30002"  />
     <dubbo :protocol name = "dubbo" port = "2288" host = "10.132.171.146" ></dubbo :protocol >    
     <dubbo :service id = "serviceDubbo"  interface = "IInterface" ref = "detailService" version = "${dubbo.version}" timeout = "60000" ></dubbo :service >


2,之前提到过,Dubbo定义了自己的Schemal并自己解析。我们查看ServiceBean,该类用来解析对应的Dubbo命名空间的文档。

public  class ServiceBean <T >  extends ServiceConfig <T > implements InitializingBean , DisposableBean , ApplicationContextAware , ApplicationListener , BeanNameAware

该类实现了一系列Spring初始化Bean的方法,并继承了SerivceConfig。在Bean初始化时候,会调用一些Bean的初始化方法。

public void onApplicationEvent (ApplicationEvent event )  {
         if  (ContextRefreshedEvent . class .getName ( ) .equals (event .getClass ( ) .getName ( ) ) )  {
             if  (isDelay ( )  &&  ! isExported ( )  &&  ! isUnexported ( ) )  {
                 if  (logger .isInfoEnabled ( ) )  {
                    logger .info ( "The service ready on spring started. service: "  + getInterface ( ) ) ;
                 }
                export ( ) ;
             }
         }
     }

在onApplicationEvent事件中,调用了export方法。

public synchronized void export ( )  {
         if  (provider  !=  null )  {
             if  (export  ==  null )  {
                export  = provider .getExport ( ) ;
             }
             if  (delay  ==  null )  {
                delay  = provider .getDelay ( ) ;
             }
         }
         if  (export  !=  null  &&  ! export .booleanValue ( ) )  {
             return ;
         }
         if  (delay  !=  null  && delay  >  0 )  {
            Thread thread  =  new Thread ( new Runnable ( )  {
                 public void run ( )  {
                    try  {
                        Thread . sleep (delay ) ;
                     } catch  (Throwable e )  {
                     }
                    doExport ( ) ;
                 }
             } ) ;
            thread .setDaemon ( true ) ;
            thread .setName ( "DelayExportServiceThread" ) ;
            thread .start ( ) ;
         }  else  {
            doExport ( ) ;
         }
     }

继续查看doExport方法。

protected synchronized void doExport() {
        if (unexported) {
            throw new IllegalStateException("Already unexported!");
        }
        if (exported) {
            return;
        }
        exported = true;
        if (interfaceName == null || interfaceName.length() == 0) {
            throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
        }
        checkDefault();
        if (provider != null) {
            if (application == null) {
                application = provider.getApplication();
            }
            if (module == null) {
                module = provider.getModule();
            }
            if (registries == null) {
                registries = provider.getRegistries();
            }
            if (monitor == null) {
                monitor = provider.getMonitor();
            }
            if (protocols == null) {
                protocols = provider.getProtocols();
            }
        }
        if (module != null) {
            if (registries == null) {
                registries = module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
        if (application != null) {
            if (registries == null) {
                registries = application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
        if (ref instanceof GenericService) {
            interfaceClass = GenericService.class;
            if (StringUtils.isEmpty(generic)) {
                generic = Boolean.TRUE.toString();
            }
        } else {
            try {
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            checkInterfaceAndMethods(interfaceClass, methods);
            checkRef();
            generic = Boolean.FALSE.toString();
        }
        if(local !=null){
            if(local=="true"){
                local=interfaceName+"Local";
            }
            Class <? > localClass ;
            try  {
                localClass  = ClassHelper .forNameWithThreadContextClassLoader (local ) ;
             } catch  (ClassNotFoundException e )  {
                 throw  new IllegalStateException (e .getMessage ( ) , e ) ;
             }
             if ( !interfaceClass .isAssignableFrom (localClass ) ) {
                 throw  new IllegalStateException ( "The local implemention class "  + localClass .getName ( )  +  " not implement interface "  + interfaceName ) ;
             }
         }
         if (stub  != null ) {
             if (stub == "true" ) {
                stub =interfaceName + "Stub" ;
             }
            Class <? > stubClass;
            try {
                stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if(!interfaceClass.isAssignableFrom(stubClass)){
                throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + interfaceName);
            }
        }
        checkApplication();
        checkRegistry();
        checkProtocol();
        appendProperties(this);
        checkStubAndMock(interfaceClass);
        if (path == null || path.length() == 0) {
            path = interfaceName;
        }
        doExportUrls();
    }

最后到最终的方法暴漏:
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        String name = protocolConfig.getName();
        if (name == null || name.length() == 0) {
            name = "dubbo";
        }
        String host = protocolConfig.getHost();
        if (provider != null && (host == null || host.length() == 0)) {
            host = provider.getHost();
        }
        boolean anyhost = false;
        if (NetUtils.isInvalidLocalHost(host)) {
            anyhost = true;
            try {
                host = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                logger.warn(e.getMessage(), e);
            }
            if (NetUtils.isInvalidLocalHost(host)) {
                if (registryURLs != null && registryURLs.size() > 0) {
                    for (URL registryURL : registryURLs) {
                        try {
                            Socket socket = new Socket();
                            try {
                                SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
                                socket.connect(addr, 1000);
                                host = socket.getLocalAddress().getHostAddress();
                                break;
                            } finally {
                                try {
                                    socket.close();
                                } catch (Throwable e) {}
                            }
                        } catch (Exception e) {
                            logger.warn(e.getMessage(), e);
                        }
                    }
                }
                if (NetUtils.isInvalidLocalHost(host)) {
                    host = NetUtils.getLocalHost();
                }
            }
        }
        Integer port = protocolConfig.getPort();
        if (provider != null && (port == null || port == 0)) {
            port = provider.getPort();
        }
        final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
        if (port == null || port == 0) {
            port = defaultPort;
        }
        if (port == null || port <= 0) {
            port = getRandomPort(name);
            if (port == null || port < 0) {
                port = NetUtils.getAvailablePort(defaultPort);
                putRandomPort(name, port);
            }
            logger.warn("Use random available port(" + port + ") for protocol " + name);
        }
        Map<String, String> map = new HashMap<String, String>();
        if (anyhost) {
            map.put(Constants.ANYHOST_KEY, "true");
        }
        map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
        map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
        map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
        if (ConfigUtils.getPid() > 0) {
            map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
        }
        appendParameters(map, application);
        appendParameters(map, module);
        appendParameters(map, provider, Constants.DEFAULT_KEY);
        appendParameters(map, protocolConfig);
        appendParameters(map, this);
        if (methods != null && methods.size() > 0) {
            for (MethodConfig method : methods) {
                appendParameters(map, method, method.getName());
                String retryKey = method.getName() + ".retry";
                if (map.containsKey(retryKey)) {
                    String retryValue = map.remove(retryKey);
                    if ("false".equals(retryValue)) {
                        map.put(method.getName() + ".retries", "0");
                    }
                }
                List<ArgumentConfig> arguments = method.getArguments();
                if (arguments != null && arguments.size() > 0) {
                    for (ArgumentConfig argument : arguments) {
                        //类型自动转换.
                        if(argument.getType() != null && argument.getType().length() >0){
                            Method[] methods = interfaceClass.getMethods();
                            //遍历所有方法
                            if(methods != null && methods.length > 0){
                                for (int i = 0; i < methods.length; i++) {
                                    String methodName = methods[i].getName();
                                    //匹配方法名称,获取方法签名.
                                    if(methodName.equals(method.getName())){
                                        Class <? > [ ] argtypes  = methods [i ] .getParameterTypes ( ) ;
                                         //一个方法中单个callback
                                         if  (argument .getIndex ( )  !=  - 1  ) {
                                             if  (argtypes [argument .getIndex ( ) ] .getName ( ) .equals (argument . getType ( ) ) ) {
                                                appendParameters (map , argument , method .getName ( )  +  "."  + argument .getIndex ( ) ) ;
                                             } else  {
                                                 throw  new IllegalArgumentException ( "argument config error : the index attribute and type attirbute not match :index :" +argument .getIndex ( )  +  ", type:"  + argument . getType ( ) ) ;
                                             }
                                         }  else  {
                                             //一个方法中多个callback
                                             for  (int j  =  0  ;j <argtypes .length  ;j ++ )  {
                                                Class <? > argclazz = argtypes[j];
                                                if (argclazz.getName().equals(argument.getType())){
                                                    appendParameters(map, argument, method.getName() + "." + j);
                                                    if (argument.getIndex() != -1 && argument.getIndex() != j){
                                                        throw new IllegalArgumentException("argument config error : the index attribute and type attirbute not match :index :"+argument.getIndex() + ", type:" + argument.getType());
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }else if(argument.getIndex() != -1){
                            appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                        }else {
                            throw new IllegalArgumentException("argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
                        }
                    }
                }
            } // end of methods for
        }
        if (ProtocolUtils.isGeneric(generic)) {
            map.put("generic", generic);
            map.put("methods", Constants.ANY_VALUE);
        } else {
            String revision = Version.getVersion(interfaceClass, version);
            if (revision != null && revision.length() > 0) {
                map.put("revision", revision);
            }
            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
            if(methods.length == 0) {
                logger.warn("NO method found in service interface " + interfaceClass.getName());
                map.put("methods", Constants.ANY_VALUE);
            }
            else {
                map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
            }
        }
        if (! ConfigUtils.isEmpty(token)) {
            if (ConfigUtils.isDefault(token)) {
                map.put("token", UUID.randomUUID().toString());
            } else {
                map.put("token", token);
            }
        }
        if ("injvm".equals(protocolConfig.getName())) {
            protocolConfig.setRegister(false);
            map.put("notify", "false");
        }
        // 导出服务
        String contextPath = protocolConfig.getContextpath();
        if ((contextPath == null || contextPath.length() == 0) && provider != null) {
            contextPath = provider.getContextpath();
        }
        URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);
        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .hasExtension(url.getProtocol())) {
            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
        }
        String scope = url.getParameter(Constants.SCOPE_KEY);
        //配置为none不暴露
        if (! Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
            //配置不是remote的情况下做本地暴露 (配置为remote,则表示只暴露远程服务)
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
            //如果配置不是local则暴露为远程服务.(配置为local,则表示只暴露远程服务)
            if (! Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope) ){
                if (logger.isInfoEnabled()) {
                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
                }
                if (registryURLs != null && registryURLs.size() > 0
                        && url.getParameter("register", true)) {
                    for (URL registryURL : registryURLs) {
                        url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                        }
                        if (logger.isInfoEnabled()) {
                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                        }
                        Invoker <? > invoker  = proxyFactory .getInvoker (ref ,  ( Class ) interfaceClass , registryURL .addParameterAndEncoded (Constants .EXPORT_KEY , url .toFullString ( ) ) ) ;
                        Exporter <? > exporter = protocol.export(invoker);
                        exporters.add(exporter);
                    }
                } else {
                    Invoker <? > invoker  = proxyFactory .getInvoker (ref ,  ( Class ) interfaceClass , url ) ;
                    Exporter <? > exporter = protocol.export(invoker);
                    exporters.add(exporter);
                }
            }
        }
        this.urls.add(url);
    }

这个是比较主要的一条线,我们可以较为简单的分析一些实现。

你可能感兴趣的:(Dubbo容器--Provider)