SOFARPC源码解析-服务发布

简介摘要
SOFARPC是蚂蚁金服开源的高可扩展性、高性能、生产级的轻量级Java RPC服务框架,基于Netty网络通信框架提供应用之间的点对点服务调用功能,为应用之间提供点对点远程服务调用功能。SOFARPC服务发布按照编程界面分为两种使用SOFARPC的方式:
1.通过SOFARPC使用:
服务发布过程涉及到RegistryConfig注册中心配置类,ServerConfig 服务运行容器配置类以及ProviderConfig服务发布配置类。
(1)RegistryConfig注册中心配置类

RegistryConfig registryConfig = new RegistryConfig()
            .setProtocol("zookeeper")
            .setAddress("127.0.0.1:2181")

RegistryConfig表示注册中心,如上声明服务注册中心的地址和端口是127.0.0.1:2181,协议是Zookeeper。
(2)ServerConfig服务运行容器配置类

ServerConfig serverConfig = new ServerConfig()
           .setPort(8803)
           .setProtocol("bolt");

ServerConfig表示服务运行容器,如上声明一个使用8803端口和bolt 协议的server。
(3)ProviderConfig服务发布配置类

ProviderConfig<HelloWorldService> providerConfig = new ProviderConfig<HelloWorldService>()
            .setInterfaceId(HelloWorldService.class.getName())    
            .setRef(new HelloWorldServiceImpl())    
            .setServer(serverConfig)  
            .setRegistry(registryConfig);
providerConfig.export();

ProviderConfig表示服务发布,如上声明服务的接口,实现和该服务运行的server,最终通过export方法将此服务发布出去。
SOFARPC服务发布支持如下特性:
(1)同一服务发布bolt,rest,dubbo多种协议,构建多个ServerConfig设置给ProviderConfig:

 List<ServerConfig> serverConfigs = new ArrayList<ServerConfig>();
 serverConfigs.add(serverConfigA);
 serverConfigs.add(serverConfigB);
 providerConfig.setServer(serverConfigs);

(2)同一服务注册多个注册中心,构建多个RegistryConfig设置给 ProviderConfig:

List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
registryConfigs.add(registryA);
registryConfigs.add(registryB);
providerConfig.setRegistry(registryConfigs);

(3)提供MethodConfig进行方法级别参数设置,API方式使用相应的对象set法即可为其设置参数:

MethodConfig methodConfigA = new MethodConfig();
MethodConfig methodConfigB = new MethodConfig();
List<MethodConfig> methodConfigs = new ArrayList<MethodConfig>();
methodConfigs.add(methodConfigA);
methodConfigs.add(methodConfigB);   
providerConfig.setMethods(methodConfigs);  //服务端设置

2.通过SOFABoot使用:
(1)服务发布使用XML配置通过sofa:service元素表示发布服务,XML配置如下所示就能够发布SOFARPC服务:

<bean id="helloSyncServiceImpl" class="com.alipay.sofa.rpc.samples.invoke.HelloSyncServiceImpl"/>
<sofa:service ref="helloSyncServiceImpl" interface="com.alipay.sofa.rpc.samples.invoke.HelloSyncService">
    <sofa:binding.bolt/>
</sofa:service>

如上声明服务实现helloSyncServiceImpl,通过sofa:service元素将该服务发布,其中ref属性表示发布的服务实例,interface属性表示该服务的接口。而sofa:binding.bolt元素表示该服务会提供 bolt 协议调用通道。
当SOFARPC应用启动的时候发现当前应用需要发布RPC服务的话,SOFARPC将这些服务注册到服务注册中心上面。服务发布将该服务实例注册到对应协议的server上,并且发布该服务的元数据信息到注册中心。
一个服务也可以通过多种协议进行发布,并且通过sofa:method元素表示方法级别配置,XML配置如下所示:

<sofa:service ref="helloSyncServiceImpl" interface="com.alipay.sofa.rpc.samples.invoke.HelloSyncService">
    <sofa:binding.bolt/>
    <sofa:binding.rest/>
    <sofa:binding.dubbo/>
</sofa:service>
<sofa:service ref="sampleFacadeImpl" interface="com.alipay.sofa.rpc.bean.SampleFacade">
    <sofa:binding.bolt>
        <sofa:global-attrs timeout="3000"/>
        <sofa:method name="sayName" timeout="2000"/>
    </sofa:binding.bolt>
</sofa:service>

(2)服务发布使用注解方式通过@SofaService注解表示发布服务,interfaceType元素指定服务接口,bindings元素指定协议类型(多协议场景使用@SofaServiceBinding注解bindingType元素指定协议类型):

@SofaService(interfaceType = AnnotationService.class, bindings = { @SofaServiceBinding(bindingType = "bolt") })
@Component
public class AnnotationServiceImpl implements AnnotationService {
    @Override
    public String sayAnnotation(String stirng) {
        return stirng;
    }
}

源码解析
搭建环境服务发布示例:

package org.alipay.sofa.rpc;

import com.alipay.sofa.rpc.config.ProviderConfig;
import com.alipay.sofa.rpc.config.ServerConfig;

public class RpcServer {

    public static void main(String[] args) {
        ServerConfig serverConfig = new ServerConfig()
                .setProtocol("bolt") // 设置一个协议,默认bolt
                .setPort(12800) // 设置一个端口,默认12200
                .setDaemon(false); // 非守护线程

        ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>()
                .setInterfaceId(HelloService.class.getName()) // 指定接口
                .setRef(new HelloServiceImpl()) // 指定实现
                .setServer(serverConfig); // 指定服务端

        providerConfig.export(); // 发布服务
    }
}

参考SOFARPC Example示例模块(com.alipay.sofa.rpc.quickstart.QuickStartServer):

package com.alipay.sofa.rpc.quickstart;

import com.alipay.sofa.rpc.config.ProviderConfig;
import com.alipay.sofa.rpc.config.ServerConfig;

/**
 * Quick Start Server
 */
public class QuickStartServer {

    public static void main(String[] args) {
        ServerConfig serverConfig = new ServerConfig()
            .setProtocol("bolt") // 设置一个协议,默认bolt
            .setPort(12000) // 设置一个端口,默认12200
            .setDaemon(false); // 非守护线程

        ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>()
            .setInterfaceId(HelloService.class.getName()) // 指定接口
            .setRef(new HelloServiceImpl()) // 指定实现
            .setServer(serverConfig); // 指定服务端

        providerConfig.export(); // 发布服务
    }
}

运行服务发布端示例类QuickStartServer查看提供端运行效果,服务提供者输出日志如下:

Connected to the target VM, address: '127.0.0.1:59510', transport: 'socket'
2018-05-14 15:34:11,927 main  INFO [com.alipay.sofa.rpc.context.RpcRuntimeContext:info:102] - Welcome! Loading SOFA RPC Framework : 5.4.0_20180427231325, PID is:1952
2018-05-14 15:34:14,752 main  INFO [com.alipay.sofa.rpc.module.ModuleFactory:info:102] - Install Module: fault-tolerance
2018-05-14 15:34:54,347 main  INFO [com.alipay.sofa.rpc.bootstrap.DefaultProviderBootstrap:infoWithApp:122] - Export provider config : com.alipay.sofa.rpc.quickstart.HelloService: with bean id rpc-cfg-0
Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.remoting Log4j ]
2018-05-14 15:35:59,083 main  INFO [com.alipay.sofa.common.log:report:30] - Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.remoting Log4j ]

参考sofa-rpc-boot-projects范例模块(com.alipay.sofa.rpc.samples.annotation):

package com.alipay.sofa.rpc.samples.annotation;

public interface AnnotationService {

    String sayAnnotation(String stirng);

}
package com.alipay.sofa.rpc.samples.annotation;

import com.alipay.sofa.runtime.api.annotation.SofaService;
import com.alipay.sofa.runtime.api.annotation.SofaServiceBinding;
import org.springframework.stereotype.Component;

@SofaService(interfaceType = AnnotationService.class, bindings = { @SofaServiceBinding(bindingType = "bolt") })
@Component
public class AnnotationServiceImpl implements AnnotationService {
    @Override
    public String sayAnnotation(String stirng) {
        return stirng;
    }
}
package com.alipay.sofa.rpc.samples.annotation;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
public class AnnotationServerApplication {

    public static void main(String[] args) {

        SpringApplication springApplication = new SpringApplication(AnnotationServerApplication.class);
        ApplicationContext applicationContext = springApplication.run(args);
    }
}

运行服务发布端范例类AnnotationServerApplication查看提供端运行效果,服务提供者输出日志如下:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.2.RELEASE)

Sofa-Middleware-Log SLF4J : Actual logging.path is [ ./logs ]
2018-06-06 00:25:01.856  INFO 14648 --- [           main] com.alipay.sofa.common.log               : Sofa-Middleware-Log SLF4J : Actual logging.path is [ ./logs ]
Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.infra Logback ]
2018-06-06 00:25:02.000  INFO 14648 --- [           main] com.alipay.sofa.common.log               : Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.infra Logback ]
Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.healthcheck Logback ]
2018-06-06 00:25:02.265  INFO 14648 --- [           main] com.alipay.sofa.common.log               : Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.healthcheck Logback ]
2018-06-06 00:25:02.512  INFO 14648 --- [           main] c.a.s.r.s.a.AnnotationServerApplication  : Starting AnnotationServerApplication on Program with PID 14648 (D:\Program\Github\sofa-rpc-boot-projects\sofa-boot-samples\target\classes started by Administrator in D:\Program\Github\sofa-rpc-boot-projects)
2018-06-06 00:25:02.514  INFO 14648 --- [           main] c.a.s.r.s.a.AnnotationServerApplication  : No active profile set, falling back to default profiles: default
2018-06-06 00:25:02.836  INFO 14648 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4c12331b: startup date [Wed Jun 06 00:25:02 CST 2018]; root of context hierarchy
2018-06-06 00:25:07.133  INFO 14648 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'com.alipay.sofa.runtime.spring.configuration.SofaRuntimeAutoConfiguration' of type [class com.alipay.sofa.runtime.spring.configuration.SofaRuntimeAutoConfiguration$$EnhancerBySpringCGLIB$$75b40bdf] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-06-06 00:25:07.254  INFO 14648 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'bindingConverterFactory' of type [class com.alipay.sofa.runtime.service.impl.BindingConverterFactoryImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-06-06 00:25:07.292  INFO 14648 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'bindingAdapterFactory' of type [class com.alipay.sofa.runtime.service.impl.BindingAdapterFactoryImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-06-06 00:25:07.311  INFO 14648 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'sofaRuntimeProperties' of type [class com.alipay.sofa.runtime.spring.config.SofaRuntimeProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-06-06 00:25:07.336  INFO 14648 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'sofaRuntimeContext' of type [class com.alipay.sofa.runtime.spi.component.SofaRuntimeContext] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-06-06 00:25:09.229  INFO 14648 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-06-06 00:25:09.253  INFO 14648 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2018-06-06 00:25:09.256  INFO 14648 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.6
2018-06-06 00:25:10.000  INFO 14648 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-06-06 00:25:10.001  INFO 14648 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 7165 ms
2018-06-06 00:25:10.773  INFO 14648 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2018-06-06 00:25:10.785  INFO 14648 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'metricsFilter' to: [/*]
2018-06-06 00:25:10.786  INFO 14648 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-06-06 00:25:10.786  INFO 14648 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-06-06 00:25:10.787  INFO 14648 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-06-06 00:25:10.787  INFO 14648 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-06-06 00:25:10.787  INFO 14648 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'webRequestLoggingFilter' to: [/*]
2018-06-06 00:25:10.788  INFO 14648 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'applicationContextIdFilter' to: [/*]
Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.runtime Logback ]
2018-06-06 00:25:11.020  INFO 14648 --- [           main] com.alipay.sofa.common.log               : Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.runtime Logback ]
Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.rpc Logback ]
2018-06-06 00:25:11.560  INFO 14648 --- [           main] com.alipay.sofa.common.log               : Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.rpc Logback ]
2018-06-06 00:25:12.044  INFO 14648 --- [           main] o.a.c.f.imps.CuratorFrameworkImpl        : Starting
2018-06-06 00:25:12.060  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT
2018-06-06 00:25:12.061  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:host.name=Program
2018-06-06 00:25:12.061  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:java.version=1.8.0_141
2018-06-06 00:25:12.061  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:java.vendor=Oracle Corporation
2018-06-06 00:25:12.061  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:java.home=C:\Program Files\Java\jdk1.8.0_141\jre
2018-06-06 00:25:12.062  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:java.class.path=C:\Program Files\Java\jdk1.8.0_141\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_141\jre\lib\rt.jar;D:\Program\Github\sofa-rpc-boot-projects\sofa-boot-samples\target\classes;D:\Program\Github\sofa-rpc-boot-projects\sofa-boot-starter\target\classes;C:\Users\Administrator\.m2\repository\com\alipay\sofa\sofa-rpc-all\5.4.0\sofa-rpc-all-5.4.0.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\bolt\1.4.1\bolt-1.4.1.jar;C:\Users\Administrator\.m2\repository\org\slf4j\slf4j-api\1.7.21\slf4j-api-1.7.21.jar;C:\Users\Administrator\.m2\repository\io\netty\netty-all\4.1.25.Final\netty-all-4.1.25.Final.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\hessian\3.3.0\hessian-3.3.0.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\tracer-core\2.1.1\tracer-core-2.1.1.jar;C:\Users\Administrator\.m2\repository\io\opentracing\opentracing-api\0.22.0\opentracing-api-0.22.0.jar;C:\Users\Administrator\.m2\repository\io\opentracing\opentracing-noop\0.22.0\opentracing-noop-0.22.0.jar;C:\Users\Administrator\.m2\repository\io\opentracing\opentracing-mock\0.22.0\opentracing-mock-0.22.0.jar;C:\Users\Administrator\.m2\repository\io\opentracing\opentracing-util\0.22.0\opentracing-util-0.22.0.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\lookout\lookout-api\1.4.0\lookout-api-1.4.0.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\runtime-sofa-boot-starter\2.4.0\runtime-sofa-boot-starter-2.4.0.jar;C:\Users\Administrator\.m2\repository\org\apache\curator\curator-client\2.9.1\curator-client-2.9.1.jar;C:\Users\Administrator\.m2\repository\org\apache\curator\curator-framework\2.9.1\curator-framework-2.9.1.jar;C:\Users\Administrator\.m2\repository\org\apache\curator\curator-recipes\2.9.1\curator-recipes-2.9.1.jar;C:\Users\Administrator\.m2\repository\org\jboss\resteasy\resteasy-jaxrs\3.0.12.Final\resteasy-jaxrs-3.0.12.Final.jar;C:\Users\Administrator\.m2\repository\org\jboss\spec\javax\annotation\jboss-annotations-api_1.1_spec\1.0.1.Final\jboss-annotations-api_1.1_spec-1.0.1.Final.jar;C:\Users\Administrator\.m2\repository\javax\activation\activation\1.1.1\activation-1.1.1.jar;C:\Users\Administrator\.m2\repository\org\apache\httpcomponents\httpclient\4.3.6\httpclient-4.3.6.jar;C:\Users\Administrator\.m2\repository\org\apache\httpcomponents\httpcore\4.3.3\httpcore-4.3.3.jar;C:\Users\Administrator\.m2\repository\commons-logging\commons-logging\1.1.3\commons-logging-1.1.3.jar;C:\Users\Administrator\.m2\repository\commons-codec\commons-codec\1.6\commons-codec-1.6.jar;C:\Users\Administrator\.m2\repository\commons-io\commons-io\2.1\commons-io-2.1.jar;C:\Users\Administrator\.m2\repository\net\jcip\jcip-annotations\1.0\jcip-annotations-1.0.jar;C:\Users\Administrator\.m2\repository\org\jboss\resteasy\resteasy-client\3.0.12.Final\resteasy-client-3.0.12.Final.jar;C:\Users\Administrator\.m2\repository\org\jboss\resteasy\resteasy-jackson-provider\3.0.12.Final\resteasy-jackson-provider-3.0.12.Final.jar;C:\Users\Administrator\.m2\repository\org\codehaus\jackson\jackson-core-asl\1.9.12\jackson-core-asl-1.9.12.jar;C:\Users\Administrator\.m2\repository\org\codehaus\jackson\jackson-mapper-asl\1.9.12\jackson-mapper-asl-1.9.12.jar;C:\Users\Administrator\.m2\repository\org\codehaus\jackson\jackson-jaxrs\1.9.12\jackson-jaxrs-1.9.12.jar;C:\Users\Administrator\.m2\repository\org\codehaus\jackson\jackson-xc\1.9.12\jackson-xc-1.9.12.jar;C:\Users\Administrator\.m2\repository\org\jboss\resteasy\resteasy-netty4\3.0.12.Final\resteasy-netty4-3.0.12.Final.jar;C:\Users\Administrator\.m2\repository\org\jboss\resteasy\resteasy-validator-provider-11\3.0.12.Final\resteasy-validator-provider-11-3.0.12.Final.jar;C:\Users\Administrator\.m2\repository\org\hibernate\hibernate-validator\5.0.1.Final\hibernate-validator-5.0.1.Final.jar;C:\Users\Administrator\.m2\repository\javax\validation\validation-api\1.1.0.Final\validation-api-1.1.0.Final.jar;C:\Users\Administrator\.m2\repository\org\jboss\logging\jboss-logging\3.1.1.GA\jboss-logging-3.1.1.GA.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\classmate\0.8.0\classmate-0.8.0.jar;C:\Users\Administrator\.m2\repository\org\jboss\resteasy\jaxrs-api\3.0.12.Final\jaxrs-api-3.0.12.Final.jar;C:\Users\Administrator\.m2\repository\org\jboss\resteasy\resteasy-multipart-provider\3.0.12.Final\resteasy-multipart-provider-3.0.12.Final.jar;C:\Users\Administrator\.m2\repository\org\jboss\resteasy\resteasy-jaxb-provider\3.0.12.Final\resteasy-jaxb-provider-3.0.12.Final.jar;C:\Users\Administrator\.m2\repository\com\sun\xml\bind\jaxb-impl\2.2.7\jaxb-impl-2.2.7.jar;C:\Users\Administrator\.m2\repository\com\sun\xml\bind\jaxb-core\2.2.7\jaxb-core-2.2.7.jar;C:\Users\Administrator\.m2\repository\javax\xml\bind\jaxb-api\2.2.7\jaxb-api-2.2.7.jar;C:\Users\Administrator\.m2\repository\com\sun\istack\istack-commons-runtime\2.16\istack-commons-runtime-2.16.jar;C:\Users\Administrator\.m2\repository\com\sun\xml\fastinfoset\FastInfoset\1.2.12\FastInfoset-1.2.12.jar;C:\Users\Administrator\.m2\repository\javax\xml\bind\jsr173_api\1.0\jsr173_api-1.0.jar;C:\Users\Administrator\.m2\repository\javax\mail\mail\1.5.0-b01\mail-1.5.0-b01.jar;C:\Users\Administrator\.m2\repository\org\apache\james\apache-mime4j\0.6\apache-mime4j-0.6.jar;C:\Users\Administrator\.m2\repository\javax\el\javax.el-api\2.2.5\javax.el-api-2.2.5.jar;C:\Users\Administrator\.m2\repository\org\glassfish\web\javax.el\2.2.6\javax.el-2.2.6.jar;C:\Users\Administrator\.m2\repository\com\alibaba\dubbo\2.4.10\dubbo-2.4.10.jar;C:\Users\Administrator\.m2\repository\org\jboss\netty\netty\3.2.5.Final\netty-3.2.5.Final.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-beans\4.3.4.RELEASE\spring-beans-4.3.4.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-core\4.3.4.RELEASE\spring-core-4.3.4.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\1.4.2.RELEASE\spring-boot-autoconfigure-1.4.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\test-sofa-boot-starter\2.4.0\test-sofa-boot-starter-2.4.0.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\healthcheck-sofa-boot-starter\2.4.0\healthcheck-sofa-boot-starter-2.4.0.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\infra-sofa-boot-starter\2.4.0\infra-sofa-boot-starter-2.4.0.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-context\4.3.4.RELEASE\spring-context-4.3.4.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-aop\4.3.4.RELEASE\spring-aop-4.3.4.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-expression\4.3.4.RELEASE\spring-expression-4.3.4.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot\1.4.2.RELEASE\spring-boot-1.4.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-actuator\1.4.2.RELEASE\spring-boot-starter-actuator-1.4.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter\1.4.2.RELEASE\spring-boot-starter-1.4.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-logging\1.4.2.RELEASE\spring-boot-starter-logging-1.4.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-classic\1.1.7\logback-classic-1.1.7.jar;C:\Users\Administrator\.m2\repository\ch\qos\logback\logback-core\1.1.7\logback-core-1.1.7.jar;C:\Users\Administrator\.m2\repository\org\slf4j\jcl-over-slf4j\1.7.21\jcl-over-slf4j-1.7.21.jar;C:\Users\Administrator\.m2\repository\org\slf4j\jul-to-slf4j\1.7.21\jul-to-slf4j-1.7.21.jar;C:\Users\Administrator\.m2\repository\org\slf4j\log4j-over-slf4j\1.7.21\log4j-over-slf4j-1.7.21.jar;C:\Users\Administrator\.m2\repository\org\yaml\snakeyaml\1.17\snakeyaml-1.17.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-actuator\1.4.2.RELEASE\spring-boot-actuator-1.4.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-web\1.4.2.RELEASE\spring-boot-starter-web-1.4.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\1.4.2.RELEASE\spring-boot-starter-tomcat-1.4.2.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\8.5.6\tomcat-embed-core-8.5.6.jar;C:\Users\Administrator\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\8.5.6\tomcat-embed-el-8.5.6.jar;C:\Users\Administrator\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\8.5.6\tomcat-embed-websocket-8.5.6.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.8.4\jackson-databind-2.8.4.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.8.0\jackson-annotations-2.8.0.jar;C:\Users\Administrator\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.8.4\jackson-core-2.8.4.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-web\4.3.4.RELEASE\spring-web-4.3.4.RELEASE.jar;C:\Users\Administrator\.m2\repository\org\springframework\spring-webmvc\4.3.4.RELEASE\spring-webmvc-4.3.4.RELEASE.jar;C:\Users\Administrator\.m2\repository\com\alibaba\fastjson\1.2.47\fastjson-1.2.47.jar;C:\Users\Administrator\.m2\repository\com\alipay\sofa\common\sofa-common-tools\1.0.12\sofa-common-tools-1.0.12.jar;C:\Users\Administrator\.m2\repository\org\apache\curator\curator-test\2.9.1\curator-test-2.9.1.jar;C:\Users\Administrator\.m2\repository\org\apache\zookeeper\zookeeper\3.4.6\zookeeper-3.4.6.jar;C:\Users\Administrator\.m2\repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;C:\Users\Administrator\.m2\repository\jline\jline\0.9.94\jline-0.9.94.jar;C:\Users\Administrator\.m2\repository\io\netty\netty\3.7.0.Final\netty-3.7.0.Final.jar;C:\Users\Administrator\.m2\repository\org\javassist\javassist\3.18.1-GA\javassist-3.18.1-GA.jar;C:\Users\Administrator\.m2\repository\org\apache\commons\commons-math\2.2\commons-math-2.2.jar;C:\Users\Administrator\.m2\repository\com\google\guava\guava\16.0.1\guava-16.0.1.jar;C:\Users\Administrator\.m2\repository\com\101tec\zkclient\0.10\zkclient-0.10.jar;D:\Program\JetBrains\IntelliJ\lib\idea_rt.jar
2018-06-06 00:25:12.066  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:java.library.path=C:\Program Files\Java\jdk1.8.0_141\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\ProgramData\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\Java\jdk1.8.0_141\bin;C:\Program Files\Java\jdk1.8.0_141\jre\bin;C:\Program Files\Maven\bin;C:\Program Files (x86)\Git\cmd;C:\Program Files\MySQL\MySQL Utilities 1.6\;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;;C:\Program Files\Mercurial;.
2018-06-06 00:25:12.066  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:java.io.tmpdir=C:\Users\ADMINI~1\AppData\Local\Temp\
2018-06-06 00:25:12.066  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:java.compiler=<NA>
2018-06-06 00:25:12.067  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:os.name=Windows 10
2018-06-06 00:25:12.067  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:os.arch=amd64
2018-06-06 00:25:12.067  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:os.version=10.0
2018-06-06 00:25:12.067  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:user.name=Administrator
2018-06-06 00:25:12.067  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:user.home=C:\Users\Administrator
2018-06-06 00:25:12.067  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Client environment:user.dir=D:\Program\Github\sofa-rpc-boot-projects
2018-06-06 00:25:12.070  INFO 14648 --- [           main] org.apache.zookeeper.ZooKeeper           : Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=60000 watcher=org.apache.curator.ConnectionState@4d0753c9
2018-06-06 00:25:12.118  INFO 14648 --- [127.0.0.1:2181)] org.apache.zookeeper.ClientCnxn          : Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
2018-06-06 00:25:12.121  INFO 14648 --- [127.0.0.1:2181)] org.apache.zookeeper.ClientCnxn          : Socket connection established to 127.0.0.1/127.0.0.1:2181, initiating session
2018-06-06 00:25:12.265  INFO 14648 --- [127.0.0.1:2181)] org.apache.zookeeper.ClientCnxn          : Session establishment complete on server 127.0.0.1/127.0.0.1:2181, sessionid = 0x10005c434e80000, negotiated timeout = 40000
2018-06-06 00:25:12.277  INFO 14648 --- [ain-EventThread] o.a.c.f.state.ConnectionStateManager     : State change: CONNECTED
2018-06-06 00:25:12.352  WARN 14648 --- [           main] org.apache.curator.utils.ZKPaths         : The version of ZooKeeper being used doesn't support Container nodes. CreateMode.PERSISTENT will be used instead.
Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.rpc.boot Logback ]
2018-06-06 00:25:13.094  INFO 14648 --- [           main] com.alipay.sofa.common.log               : Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.rpc.boot Logback ]
2018-06-06 00:25:14.686  INFO 14648 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4c12331b: startup date [Wed Jun 06 00:25:02 CST 2018]; root of context hierarchy
2018-06-06 00:25:14.901  INFO 14648 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-06-06 00:25:14.904  INFO 14648 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-06-06 00:25:15.002  INFO 14648 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-06 00:25:15.003  INFO 14648 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-06 00:25:15.108  INFO 14648 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-06 00:25:16.177  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/sofaboot/versions || /sofaboot/versions.json],produces=[application/json]}" onto public java.lang.Object com.alipay.sofa.infra.endpoint.SofaBootVersionEndpointMvcAdapter.invoke()
2018-06-06 00:25:16.183  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/env/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint.value(java.lang.String)
2018-06-06 00:25:16.184  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/env || /env.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.186  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/mappings || /mappings.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.188  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/dump || /dump.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.190  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/beans || /beans.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.192  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/info || /info.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.194  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/health || /health.json],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(java.security.Principal)
2018-06-06 00:25:16.196  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/heapdump || /heapdump.json],methods=[GET],produces=[application/octet-stream]}" onto public void org.springframework.boot.actuate.endpoint.mvc.HeapdumpMvcEndpoint.invoke(boolean,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException,javax.servlet.ServletException
2018-06-06 00:25:16.199  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/configprops || /configprops.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.201  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/logfile || /logfile.json],methods=[GET || HEAD]}" onto public void org.springframework.boot.actuate.endpoint.mvc.LogFileMvcEndpoint.invoke(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException,java.io.IOException
2018-06-06 00:25:16.211  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/metrics/{name:.*}],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint.value(java.lang.String)
2018-06-06 00:25:16.211  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/metrics || /metrics.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.213  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/trace || /trace.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.215  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/autoconfig || /autoconfig.json],methods=[GET],produces=[application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter.invoke()
2018-06-06 00:25:16.216  INFO 14648 --- [           main] o.s.b.a.e.mvc.EndpointHandlerMapping     : Mapped "{[/health/readiness || /health/readiness.json],produces=[application/json]}" onto public java.lang.Object com.alipay.sofa.healthcheck.service.SofaBootReadinessCheckMvcEndpoint.invoke(java.security.Principal)
2018-06-06 00:25:16.603  INFO 14648 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-06-06 00:25:16.684  INFO 14648 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.remoting Logback ]
2018-06-06 00:25:17.592  INFO 14648 --- [           main] com.alipay.sofa.common.log               : Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.remoting Logback ]
2018-06-06 00:25:19.261  INFO 14648 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-06-06 00:25:19.313  INFO 14648 --- [           main] c.a.s.r.s.a.AnnotationServerApplication  : Started AnnotationServerApplication in 19.767 seconds (JVM running for 21.37)

SOFARPC服务发布流程:
(1)创建服务运行容器配置类ServerConfig,设置ServerConfig实例监听端口、通信协议以及是否为守护线程(是否hold住端口,true的话随主线程退出而退出,false的话则要主动退出)等基础配置信息,当然ServerConfig除自定义设置基础配置以外,类加载自动加载配置文件获取服务运行容器默认配置:

/**
 * 服务端配置
 *
  */
public class ServerConfig extends AbstractIdConfig implements Serializable

服务运行容器配置类ServerConfig继承默认配置带ID配置类 AbstractIdConfig,服务端配置ServerConfig空构造器没有自动加载默认配置,如何实现自动通过配置文件加载服务端默认配置信息?默认配置带ID类AbstractIdConfig静态代码块调用全局的运行时上下文类RpcRuntimeContext的now()方法,通过运行时上下文类RpcRuntimeContext静态代码模块在类加载的时候读取配置文件设置服务端类ServerConfig默认配置属性:

static {
    RpcRuntimeContext.now();
}
static {
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("Welcome! Loading SOFA RPC Framework : {}, PID is:{}", Version.BUILD_VERSION, PID);
    }
    put(RpcConstants.CONFIG_KEY_RPC_VERSION, Version.RPC_VERSION);
    // 初始化一些上下文
    initContext();
    // 初始化其它模块
    ModuleFactory.installModules();
    // 增加jvm关闭事件
    if (RpcConfigs.getOrDefaultValue(RpcOptions.JVM_SHUTDOWN_HOOK, true)) {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                if (LOGGER.isWarnEnabled()) {
                    LOGGER.warn("SOFA RPC Framework catch JVM shutdown event, Run shutdown hook now.");
                }
                destroy(false);
            }
        }, "SOFA-RPC-ShutdownHook"));
    }
}

全局运行时上下文类RpcRuntimeContext首先初始化上下文自动部署的appId、appName、appInsId以及当前所在文件夹地址appPath信息:

/**
 * 初始化一些上下文
 */
private static void initContext() {
    putIfAbsent(KEY_APPID, RpcConfigs.getOrDefaultValue(APP_ID, null));
    putIfAbsent(KEY_APPNAME, RpcConfigs.getOrDefaultValue(APP_NAME, null));
    putIfAbsent(KEY_APPINSID, RpcConfigs.getOrDefaultValue(INSTANCE_ID, null));
    putIfAbsent(KEY_APPAPTH, System.getProperty("user.dir"));
}

其中通过配置加载器和操作入口RpcConfigs静态代码块在类加载的时候加载rpc-config-default.json、sofa-rpc/rpc-config.json、META-INF/sofa-rpc/rpc-config.json配置文件获取默认配置、自定义配置信息自定义配置信息存储在全部配置CFG:

static {
    init(); // 加载配置文件
}
private static void init() {
    try {
        // loadDefault
        String json = FileUtils.file2String(RpcConfigs.class, "rpc-config-default.json", "UTF-8");
        Map map = JSON.parseObject(json, Map.class);
        CFG.putAll(map);

        // loadCustom
        loadCustom("sofa-rpc/rpc-config.json");
        loadCustom("META-INF/sofa-rpc/rpc-config.json");

        // load system properties
        CFG.putAll(new HashMap(System.getProperties())); // 注意部分属性可能被覆盖为字符串
    } catch (Exception e) {
        throw new SofaRpcRuntimeException("Catch Exception when load RpcConfigs", e);
    }
}

接着扩展加载器ExtensionLoader根据需要被加载的模块列表遍历判断是否需要加载来安装模板初始化其他模块:

/**
 * 加载全部模块
 */
public static void installModules() {
    ExtensionLoader<Module> loader = ExtensionLoaderFactory.getExtensionLoader(Module.class);
    String moduleLoadList = RpcConfigs.getStringValue(RpcOptions.MODULE_LOAD_LIST);
    for (Map.Entry<String, ExtensionClass<Module>> o : loader.getAllExtensions().entrySet()) {
        String moduleName = o.getKey();
        Module module = o.getValue().getExtInstance();
        // judge need load from rpc option
        if (needLoad(moduleLoadList, moduleName)) {
            // judge need load from implement
            if (module.needLoad()) {
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("Install Module: {}", moduleName);
                }
                module.install();
                INSTALLED_MODULES.put(moduleName, module);
            } else {
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("The module " + moduleName + " does not need to be loaded.");
                }
            }
        } else {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("The module " + moduleName + " is not in the module load list.");
            }
        }
    }
}

最后根据是否主动监听JVM关闭事件(默认为true)增加JVM关闭事件监听执行反注册服务端,关闭启动端口、发布服务、调用服务、注册中心、客户端公共资源,卸载模块、钩子以及清理缓存销毁操作:

private static void destroy(boolean active) {
     RpcRunningState.setShuttingDown(true);
    for (Destroyable.DestroyHook destroyHook : DESTROY_HOOKS) {
        destroyHook.preDestroy();
    }
    List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
    for (ProviderBootstrap bootstrap : EXPORTED_PROVIDER_CONFIGS) {
        providerConfigs.add(bootstrap.getProviderConfig());
    }
    // 先反注册服务端
    List<Registry> registries = RegistryFactory.getRegistries();
    if (CommonUtils.isNotEmpty(registries) && CommonUtils.isNotEmpty(providerConfigs)) {
        for (Registry registry : registries) {
            registry.batchUnRegister(providerConfigs);
        }
    }
    // 关闭启动的端口
    ServerFactory.destroyAll();
    // 关闭发布的服务
    for (ProviderBootstrap bootstrap : EXPORTED_PROVIDER_CONFIGS) {
        bootstrap.unExport();
    }
    // 关闭调用的服务
    for (ConsumerBootstrap bootstrap : REFERRED_CONSUMER_CONFIGS) {
        ConsumerConfig config = bootstrap.getConsumerConfig();
        if (!CommonUtils.isFalse(config.getParameter(RpcConstants.HIDDEN_KEY_DESTROY))) { // 除非不让主动unrefer
            bootstrap.unRefer();
        }
    }
    // 关闭注册中心
    RegistryFactory.destroyAll();
    // 关闭客户端的一些公共资源
    ClientTransportFactory.closeAll();
    // 卸载模块
    if (!RpcRunningState.isUnitTestMode()) {
        ModuleFactory.uninstallModules();
    }
    // 卸载钩子
    for (Destroyable.DestroyHook destroyHook : DESTROY_HOOKS) {
        destroyHook.postDestroy();
    }
    // 清理缓存
    RpcCacheManager.clearAll();
    RpcRunningState.setShuttingDown(false);
    if (LOGGER.isWarnEnabled()) {
        LOGGER.warn("SOFA RPC Framework has been release all resources {}...",
            active ? "actively " : "");
    }
}

(2)创建服务发布配置类ProviderConfig,设置ProviderConfig实例接口名称(服务接口:做为服务唯一标识的组成部分)、接口实现类引用以及配置的协议列表即指定服务运行容器配置:

/**
 * 服务提供者配置
 *
 * @param <T> the type parameter
 */
public class ProviderConfig<T> extends AbstractInterfaceConfig<T, ProviderConfig<T>> implements Serializable

服务发布配置类ProviderConfig继承接口级公共配置类AbstractInterfaceConfig,能够通过集成的注册中心更新服务发布接口级别配置例如超时时间、权重等。
(3)服务发布配置类ProviderConfig负责加载更新服务发布接口级配置,根据面向对象单一职责原则,需要绑定服务提供者启动类ProviderBootstrap进行发布服务:

/**
 * 发布服务
 */
public synchronized void export() {
    if (providerBootstrap == null) {
        providerBootstrap = Bootstraps.from(this);
    }
    providerBootstrap.export();
}

首先判断服务提供者启动类ProviderBootstrap是否为空,通过发布服务辅助工具类Bootstraps根据绑定服务发布配置扩展加载工厂ExtensionLoaderFactory加载初始化ProviderBootstrap实例:

/**
 * 发布一个服务
 *
 * @param providerConfig 服务发布者配置
 * @param <T>            接口类型
 * @return 发布启动类
 */
public static <T> ProviderBootstrap<T> from(ProviderConfig<T> providerConfig) {
    String bootstrap = providerConfig.getBootstrap();
    if (StringUtils.isEmpty(bootstrap)) {
        // Use default provider bootstrap
        bootstrap = RpcConfigs.getStringValue(RpcOptions.DEFAULT_PROVIDER_BOOTSTRAP);
        providerConfig.setBootstrap(bootstrap);
    }
    ProviderBootstrap providerBootstrap = ExtensionLoaderFactory.getExtensionLoader(ProviderBootstrap.class)
        .getExtension(bootstrap, new Class[] { ProviderConfig.class }, new Object[] { providerConfig });
    return (ProviderBootstrap<T>) providerBootstrap;
}

接着发布服务包装类ProviderBootstrap通过export()方法发布服务,ProviderBootstrap基于Bolt、Rest、Dubbo网络通信协议提供三种协议服务发布实现类:BoltProviderBootstrap、RestProviderBootstrap以及DubboProviderBootstrap。默认服务提供者启动器DefaultProviderBootstrap发布服务export()方法首先判断服务发布延迟时间配置(默认0,配置为-1代表Spring加载完毕)是否大于0,启动线程睡眠指定延迟时间延迟加载,接着调用doExport()方法执行SOFARPC发布服务逻辑:

public void export() {
    if (providerConfig.getDelay() > 0) { // 延迟加载,单位毫秒
        Thread thread = factory.newThread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(providerConfig.getDelay());
                } catch (Throwable ignore) { // NOPMD
                }
                doExport();
            }
        });
        thread.start();
    } else {
        doExport();
    }
}
private void doExport() {
    if (exported) {
        return;
    }
    String key = providerConfig.buildKey();
    String appName = providerConfig.getAppName();
    // 检查参数
    checkParameters();
    if (LOGGER.isInfoEnabled(appName)) {
        LOGGER.infoWithApp(appName, "Export provider config : {} with bean id {}", key, providerConfig.getId());
    }

    // 注意同一interface,同一uniqleId,不同server情况
    AtomicInteger cnt = EXPORTED_KEYS.get(key); // 计数器
    if (cnt == null) { // 没有发布过
        cnt = CommonUtils.putToConcurrentMap(EXPORTED_KEYS, key, new AtomicInteger(0));
    }
    int c = cnt.incrementAndGet();
    int maxProxyCount = providerConfig.getRepeatedExportLimit();
    if (maxProxyCount > 0) {
        if (c > maxProxyCount) {
            cnt.decrementAndGet();
            // 超过最大数量,直接抛出异常
            throw new SofaRpcRuntimeException("Duplicate provider config with key " + key
                + " has been exported more than " + maxProxyCount + " times!"
                + " Maybe it's wrong config, please check it."
                + " Ignore this if you did that on purpose!");
        } else if (c > 1) {
            if (LOGGER.isInfoEnabled(appName)) {
                LOGGER.infoWithApp(appName, "Duplicate provider config with key {} has been exported!"
                    + " Maybe it's wrong config, please check it."
                    + " Ignore this if you did that on purpose!", key);
            }
        }
    }

    try {
        // 构造请求调用器
        providerProxyInvoker = new ProviderProxyInvoker(providerConfig);
        // 初始化注册中心
        if (providerConfig.isRegister()) {
            List<RegistryConfig> registryConfigs = providerConfig.getRegistry();
            if (CommonUtils.isNotEmpty(registryConfigs)) {
                for (RegistryConfig registryConfig : registryConfigs) {
                    RegistryFactory.getRegistry(registryConfig); // 提前初始化Registry
                }
            }
        }
        // 将处理器注册到server
        List<ServerConfig> serverConfigs = providerConfig.getServer();
        for (ServerConfig serverConfig : serverConfigs) {
            try {
                Server server = serverConfig.buildIfAbsent();
                // 注册序列化接口
                server.registerProcessor(providerConfig, providerProxyInvoker);
                if (serverConfig.isAutoStart()) {
                    server.start();
                }
            } catch (SofaRpcRuntimeException e) {
                throw e;
            } catch (Exception e) {
                LOGGER.errorWithApp(appName, "Catch exception when register processor to server: "
                    + serverConfig.getId(), e);
            }
        }

        // 注册到注册中心
        providerConfig.setConfigListener(new ProviderAttributeListener());
        register();
    } catch (Exception e) {
        cnt.decrementAndGet();
        if (e instanceof SofaRpcRuntimeException) {
            throw (SofaRpcRuntimeException) e;
        } else {
            throw new SofaRpcRuntimeException("Build provider proxy error!", e);
        }
    }

    // 记录一些缓存数据
    RpcRuntimeContext.cacheProviderConfig(this);
    exported = true;
}

默认服务提供者启动器DefaultProviderBootstrap发布服务doExport()方法执行逻辑:
(1)根据服务发布配置ProviderConfig获取服务接口、服务标签构建key以及获取应用名称appName;
(2)调用checkParameters()方法检查参数,包括检查注入的ref是否接口实现类、检查服务运行容器配置是否为空、检查方法及其黑白名单:

/**
 * for check fields and parameters of consumer config 
 */
protected void checkParameters() {
    // 检查注入的ref是否接口实现类
    Class proxyClass = providerConfig.getProxyClass();
    String key = providerConfig.buildKey();
    T ref = providerConfig.getRef();
    if (!proxyClass.isInstance(ref)) {
        throw ExceptionUtils.buildRuntime("provider.ref",
            ref == null ? "null" : ref.getClass().getName(),
            "This is not an instance of " + providerConfig.getInterfaceId()
                + " in provider config with key " + key + " !");
    }
    // server 不能为空
    if (CommonUtils.isEmpty(providerConfig.getServer())) {
        throw ExceptionUtils.buildRuntime("server", "NULL", "Value of \"server\" is not specified in provider" +
            " config with key " + key + " !");
    }
    checkMethods(proxyClass);
}
/**
 * 检查方法,例如方法名、多态(重载)方法
 * 
 * @param itfClass 接口类
 */
protected void checkMethods(Class<?> itfClass) {
    ConcurrentHashMap<String, Boolean> methodsLimit = new ConcurrentHashMap<String, Boolean>();
    for (Method method : itfClass.getMethods()) {
        String methodName = method.getName();
        if (methodsLimit.containsKey(methodName)) {
            // 重名的方法
            if (LOGGER.isWarnEnabled(providerConfig.getAppName())) {
                LOGGER.warnWithApp(providerConfig.getAppName(), "Method with same name \"" + itfClass.getName()
                    + "." + methodName + "\" exists ! The usage of overloading method in rpc is deprecated.");
            }
        }
        // 判断服务下方法的黑白名单
        Boolean include = methodsLimit.get(methodName);
        if (include == null) {
            include = inList(providerConfig.getInclude(), providerConfig.getExclude(), methodName); // 检查是否在黑白名单中
            methodsLimit.putIfAbsent(methodName, include);
        }
        providerConfig.setMethodsLimit(methodsLimit);
    }
}

(3)检验同一个服务(服务接口&服务标签相同)的发布次数是否超过服务引用配置的最大次数,超过最大数量直接抛出异常;
(4)根据服务发布配置构造请求调用器ProviderProxyInvoker,构造服务端调用链最底层是调用过滤器执行链filterChain:

/**
 * 构造执行链
 *
 * @param providerConfig 服务端配置
 */
public ProviderProxyInvoker(ProviderConfig providerConfig) {
    this.providerConfig = providerConfig;
    // 最底层是调用过滤器
    this.filterChain = FilterChain.buildProviderChain(providerConfig,
        new ProviderInvoker(providerConfig));
}

服务端调用链入口ProviderProxyInvoker根据服务发布配置通过服务端调用业务实现类ProviderInvoker初始化过滤器包装Invoker对象(隔离Filter和Service的关系,filter是单例)指定无需下一层过滤器,按照自动装载扩展实现逻辑,获取用户new实例方式注入的过滤器(优先级高),判断是否需要排除系统过滤器,解析用户通过别名方式注入的过滤器准备数据,解析自动加载的过滤器加入自定义的过滤器构造执行链:

/**
 * 构造服务端的执行链
 *
 * @param providerConfig provider配置
 * @param lastFilter     最后一个filter
 * @return filter执行链
 */
public static FilterChain buildProviderChain(ProviderConfig<?> providerConfig, FilterInvoker lastFilter) {
    /*
     * 例如自动装载扩展 A(a),B(b),C(c)  filter=[-a,d]  filterRef=[new E, new Exclude(b)]
     * 逻辑如下:
     * 1.解析config.getFilterRef(),记录E和-b
     * 2.解析config.getFilter()字符串,记录 d 和 -a,-b
     * 3.再解析自动装载扩展,a,b被排除了,所以拿到c,d
     * 4.对c d进行排序
     * 5.拿到C、D实现类
     * 6.加上自定义,返回C、D、E
     */
    // 用户通过自己new实例的方式注入的filter,优先级高
    List<Filter> customFilters = providerConfig.getFilterRef() == null ?
        new ArrayList<Filter>() : new CopyOnWriteArrayList<Filter>(providerConfig.getFilterRef());
    // 先解析是否有特殊处理
    HashSet<String> excludes = parseExcludeFilter(customFilters);

    // 准备数据:用户通过别名的方式注入的filter,需要解析
    List<ExtensionClass<Filter>> extensionFilters = new ArrayList<ExtensionClass<Filter>>();
    List<String> filterAliases = providerConfig.getFilter(); //
    if (CommonUtils.isNotEmpty(filterAliases)) {
        for (String filterAlias : filterAliases) {
            if (startsWithExcludePrefix(filterAlias)) { // 排除用的特殊字符
                excludes.add(filterAlias.substring(1));
            } else {
                ExtensionClass<Filter> filter = EXTENSION_LOADER.getExtensionClass(filterAlias);
                if (filter != null) {
                    extensionFilters.add(filter);
                }
            }
        }
    }
    // 解析自动加载的过滤器
    if (!excludes.contains(StringUtils.ALL) && !excludes.contains(StringUtils.DEFAULT)) { // 配了-*和-default表示不加载内置
        for (Map.Entry<String, ExtensionClass<Filter>> entry : PROVIDER_AUTO_ACTIVES.entrySet()) {
            if (!excludes.contains(entry.getKey())) {
                extensionFilters.add(entry.getValue());
            }
        }
    }
    excludes = null; // 不需要了
    // 按order从小到大排序
    if (extensionFilters.size() > 1) {
        Collections.sort(extensionFilters, new OrderedComparator<ExtensionClass<Filter>>());
    }
    List<Filter> actualFilters = new ArrayList<Filter>();
    for (ExtensionClass<Filter> extensionFilter : extensionFilters) {
        actualFilters.add(extensionFilter.getExtInstance());
    }
    // 加入自定义的过滤器
    actualFilters.addAll(customFilters);
    return new FilterChain(actualFilters, lastFilter, providerConfig);
}
/**
 * 构造执行链
 *
 * @param filters     包装过滤器列表
 * @param lastInvoker 最终过滤器
 * @param config      接口配置
 */
protected FilterChain(List<Filter> filters, FilterInvoker lastInvoker, AbstractInterfaceConfig config) {
    // 调用过程外面包装多层自定义filter
    // 前面的过滤器在最外层
    invokerChain = lastInvoker;
    if (CommonUtils.isNotEmpty(filters)) {
        loadedFilters = new ArrayList<Filter>();
        for (int i = filters.size() - 1; i >= 0; i--) {
            try {
                Filter filter = filters.get(i);
                if (filter.needToLoad(invokerChain)) {
                    invokerChain = new FilterInvoker(filter, invokerChain, config);
                    // cache this for filter when async respond
                    loadedFilters.add(filter);
                }
            } catch (Exception e) {
                LOGGER.error("Error when build filter chain", e);
                throw new SofaRpcRuntimeException("Error when build filter chain", e);
            }
        }
    }
}

(5)判断服务配置是否注册提前初始化注册中心,注册中心配置类RegistryConfig根据注册中心配置获取注册中心实现类Registry实例,注册中心实现类Registry包括基于本地文件注册中心LocalRegistry和基于Zookeeper分布式协调系统注册中心ZookeeperRegistry:

/**
 * 得到注册中心对象
 *
 * @param registryConfig RegistryConfig类
 * @return Registry实现
 */
public static synchronized Registry getRegistry(RegistryConfig registryConfig) {
    if (ALL_REGISTRIES.size() > 3) { // 超过3次 是不是配错了?
        if (LOGGER.isWarnEnabled()) {
            LOGGER.warn("Size of registry is greater than 3, Please check it!");
        }
    }
    try {
        // 注意:RegistryConfig重写了equals方法,如果多个RegistryConfig属性一样,则认为是一个对象
        Registry registry = ALL_REGISTRIES.get(registryConfig);
        if (registry == null) {
            ExtensionClass<Registry> ext = ExtensionLoaderFactory.getExtensionLoader(Registry.class)
                .getExtensionClass(registryConfig.getProtocol());
            if (ext == null) {
                throw ExceptionUtils.buildRuntime("registry.protocol", registryConfig.getProtocol(),
                    "Unsupported protocol of registry config !");
            }
            registry = ext.getExtInstance(new Class[] { RegistryConfig.class }, new Object[] { registryConfig });
            ALL_REGISTRIES.put(registryConfig, registry);
        }
        return registry;
    } catch (SofaRpcRuntimeException e) {
        throw e;
    } catch (Throwable e) {
        throw new SofaRpcRuntimeException(e.getMessage(), e);
    }
}

(6)根据服务发布配置ProviderConfig获取服务运行容器配置列表,遍历服务运行容器配置构建启动服务运行容器Server实例,服务运行容器Server包括基于Bolt协议的BoltServer和基于Rest协议的RestServer:

/**
 * 启动服务
 *
 * @return the server
 */
public synchronized Server buildIfAbsent() {
    if (server != null) {
        return server;
    }
    // 提前检查协议+序列化方式
    // ConfigValueHelper.check(ProtocolType.valueOf(getProtocol()),
    //                SerializationType.valueOf(getSerialization()));

    server = ServerFactory.getServer(this);
    return server;
}

通过服务运行容器工厂ServerFactory的getServer()方法获取启动基于当前服务运行容器配置ServerConfig的服务端Server实例,首先按照服务运行容器配置确定服务端Server的Host和Port,扩展加载器工厂ExtensionLoaderFactory生成服务运行容器Server实例,初始化启动服务端Server,缓存服务端Server到SERVER_MAP:

/**
 * 初始化Server实例
 *
 * @param serverConfig 服务端配置
 * @return Server
 */
public synchronized static Server getServer(ServerConfig serverConfig) {
    try {
        Server server = SERVER_MAP.get(Integer.toString(serverConfig.getPort()));
        if (server == null) {
            // 算下网卡和端口
            resolveServerConfig(serverConfig);

            ExtensionClass<Server> ext = ExtensionLoaderFactory.getExtensionLoader(Server.class)
                .getExtensionClass(serverConfig.getProtocol());
            if (ext == null) {
                throw ExceptionUtils.buildRuntime("server.protocol", serverConfig.getProtocol(),
                    "Unsupported protocol of server!");
            }
            server = ext.getExtInstance();
            server.init(serverConfig);
            SERVER_MAP.put(serverConfig.getPort() + "", server);
        }
        return server;
    } catch (SofaRpcRuntimeException e) {
        throw e;
    } catch (Throwable e) {
        throw new SofaRpcRuntimeException(e.getMessage(), e);
    }
}

默认服务运行容器BoltServer启动Server端设置服务运行容器配置引用,按照服务端业务线程池核心线程数、最大线程数、线程队列以及回收时间配置初始化业务线程池提供给RpcHandler 处理复杂业务使用,不会影响Netty IO线程运行。根据服务运行容器BoltServer创建BoltServerProcessor处理器并且支持自定义业务线程池,BoltServerProcessor处理器继承AbstractUserProcessor类实现UserProcessor接口,当调用RpcHandler处理器的channelRead(ChannelHandlerContext ctx, Object msg)方法时候,根据请求类名称获取对应的UserProcessor执行handleRequest(BizContext bizCtx, AsyncContext asyncCtx, SofaRequest request)方法查找服务调用器、请求方法实施调用方法处理请求:

public void init(ServerConfig serverConfig) {
    this.serverConfig = serverConfig;
    // 启动线程池
    bizThreadPool = initThreadPool(serverConfig);
    boltServerProcessor = new BoltServerProcessor(this);
}
protected ThreadPoolExecutor initThreadPool(ServerConfig serverConfig) {
    ThreadPoolExecutor threadPool = BusinessPool.initPool(serverConfig);
    threadPool.setThreadFactory(new NamedThreadFactory(
        "BOLT-BIZ-" + serverConfig.getPort(), serverConfig.isDaemon()));
    threadPool.setRejectedExecutionHandler(new SofaRejectedExecutionHandler());
    if (serverConfig.isPreStartCore()) { // 初始化核心线程池
        threadPool.prestartAllCoreThreads();
    }
    return threadPool;
}
/**
 * Construct
 *
 * @param boltServer 所在的Server
 */
public BoltServerProcessor(BoltServer boltServer) {
    this.boltServer = boltServer;
    this.executorSelector = new UserThreadPoolSelector(); // 支持自定义业务线程池
}
/**
 * Bolt server processor of bolt server. 
 *
 */
public class BoltServerProcessor extends AsyncUserProcessor<SofaRequest>{...}
public abstract class AsyncUserProcessor<T> extends AbstractUserProcessor<T>{...}
public abstract class AbstractUserProcessor<T> implements UserProcessor<T>{...}
public void process(RemotingContext ctx, RpcRequestCommand cmd, ExecutorService defaultExecutor) throws Exception {
    if (this.deserializeRequestCommand(ctx, cmd, 0)) {
        UserProcessor userProcessor = ctx.getUserProcessor(cmd.getRequestClass());
        if (userProcessor == null) {
            String errMsg = "No user processor found for request: " + cmd.getRequestClass();
            logger.error(errMsg);
            this.sendResponseIfNecessary(ctx, cmd.getType(), this.getCommandFactory().createExceptionResponse(cmd.getId(), errMsg));
        } else {
            ctx.setTimeoutDiscard(userProcessor.timeoutDiscard());
            if (userProcessor.processInIOThread()) {
                if (this.deserializeRequestCommand(ctx, cmd, 2)) {
                    (new RpcRequestProcessor.ProcessTask(ctx, cmd)).run();
                }
            } else {
                Executor executor = null;
                if (null == userProcessor.getExecutorSelector()) {
                    executor = userProcessor.getExecutor();
                } else {
                    if (!this.deserializeRequestCommand(ctx, cmd, 1)) {
                        return;
                    }

                    executor = userProcessor.getExecutorSelector().select(cmd.getRequestClass(), cmd.getRequestHeader());
                }

                if (executor == null) {
                    executor = this.getExecutor() == null ? defaultExecutor : this.getExecutor();
                }

                ((Executor)executor).execute(new RpcRequestProcessor.ProcessTask(ctx, cmd));
            }
        }
    }
}

什么时候调用BoltServerProcessor处理器handleRequest方法执行方法调用处理请求?查看BoltServerProcessor处理器handleRequest方法调用链:
BoltServerProcessor处理器handleRequest方法调用链

BoltServerProcessor处理器handleRequest方法调用链顶端是通过RpcRequestProcessor处理器ProcessTask处理任务调用,ProcessTask任务提交给线程池处理,查看ProcessTask构造方法调用链:
ProcessTask构造方法调用链
ProcessTask构造方法调用链顶端是通过RpcHandler处理器的channelRead方法将消息分发给相应的协议,什么时候使用默认服务端BoltServer业务线程池bizThreadPool处理复杂业务?查看BoltServer服务端getBizThreadPool方法调用链:
BoltServer服务端getBizThreadPool方法调用链
BoltServer服务端getBizThreadPool方法最终也是通过RpcHandler处理器的channelRead方法调用,即获取服务端BoltServer业务线程池bizThreadPool,提交RpcRequestProcessor处理器ProcessTask任务,执行BoltServerProcessor处理器handleRequest方法处理请求。

(7)服务端Server实例注册服务提供者配置、服务端调用实现,默认服务运行容器BoltServer缓存服务端调用Invoker对象到接口--> Invoker映射invokerMap以及服务发布接口方法:

public void registerProcessor(ProviderConfig providerConfig, Invoker instance) {
    // 缓存Invoker对象
    String key = ConfigUniqueNameGenerator.getUniqueName(providerConfig);
    invokerMap.put(key, instance);
    // 缓存接口的方法
    for (Method m : providerConfig.getProxyClass().getMethods()) {
        ReflectCache.putOverloadMethodCache(key, m);
    }
}

(8)判断服务端配置ServerConfig是否自动启动,启动服务运行容器Server实例:

public void start() {
    if (started) {
        return;
    }
    synchronized (this) {
        if (started) {
            return;
        }
        // 生成Server对象
        remotingServer = initRemotingServer();
        try {
            if (!remotingServer.start(serverConfig.getBoundHost())) {
                throw new SofaRpcRuntimeException("Failed to start bolt server, see more detail from bolt log.");
            }
            started = true;
        } catch (SofaRpcRuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new SofaRpcRuntimeException("Failed to start bolt server!", e);
        }
    }
}

默认服务端BoltServer启动服务首先以服务端配置端口通过RpcServer初始化生成远程服务端Server实例,远程服务端Server将BoltServerProcessor处理器缓存到userProcessors:

protected RemotingServer initRemotingServer() {
    // 绑定到端口
    RemotingServer remotingServer = new RpcServer(serverConfig.getPort());
    remotingServer.registerUserProcessor(boltServerProcessor);
    return remotingServer;
}
public RpcServer(int port) {
    super(port);
    this.globalSwitch = new GlobalSwitch();
    this.connectionEventListener = new ConnectionEventListener();
    this.userProcessors = new ConcurrentHashMap(4);
    this.bossGroup = new NioEventLoopGroup(1, new NamedThreadFactory("Rpc-netty-server-boss"));
}
public void registerUserProcessor(UserProcessor<?> processor) {
    if (processor != null && !StringUtils.isBlank(processor.interest())) {
        UserProcessor<?> preProcessor = (UserProcessor)this.userProcessors.putIfAbsent(processor.interest(), processor);
        if (preProcessor != null) {
            String errMsg = "Processor with interest key [" + processor.interest() + "] has already been registered to rpc server, can not register again!";
            throw new RuntimeException(errMsg);
        }
    } else {
        throw new RuntimeException("User processor or processor interest should not be blank!");
    }
}

接着远程服务端Server按照服务运行容器绑定Host配置启动服务,执行init()方法初始化RpcRemoting远程连接事件处理器以及连接管理器,初始化服务启动类ServerBootstrap实例,设置服务启动类ServerBootstrap属性,根据缓存BoltServerProcessor的userProcessors创建RpcHandler处理器并且添加到ChannelPipeline,创建Rpc服务连接,执行doStart()方法服务启动类ServerBootstrap实例绑定指定IP地址同步:

public boolean start(String ip) {
    this.init();
    if (this.started.compareAndSet(false, true)) {
        try {
            logger.warn("Server started on " + ip + ":" + this.port);
            return this.doStart(ip);
        } catch (Throwable var3) {
            this.started.set(false);
            logger.error("ERROR: Failed to start the Server!", var3);
            return false;
        }
    } else {
        logger.error("ERROR: The server has already started!");
        return false;
    }
}
protected void doInit() {
    if (this.addressParser == null) {
        this.addressParser = new RpcAddressParser();
    }

    this.initRpcRemoting((RpcRemoting)null);
    this.bootstrap = new ServerBootstrap();
    ((ServerBootstrap)((ServerBootstrap)((ServerBootstrap)this.bootstrap.group(this.bossGroup, workerGroup).channel(NioServerSocketChannel.class)).option(ChannelOption.SO_BACKLOG, SystemProperties.tcp_so_backlog())).option(ChannelOption.SO_REUSEADDR, SystemProperties.tcp_so_reuseaddr())).childOption(ChannelOption.TCP_NODELAY, SystemProperties.tcp_nodelay()).childOption(ChannelOption.SO_KEEPALIVE, SystemProperties.tcp_so_keepalive());
    this.initWriteBufferWaterMark();
    boolean pooledBuffer = SystemProperties.netty_buffer_pooled();
    if (pooledBuffer) {
        ((ServerBootstrap)this.bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)).childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
    }

    final boolean idleSwitch = SystemProperties.tcp_idle_switch();
    final int idleTime = SystemProperties.tcp_server_idle();
    final ChannelHandler serverIdleHandler = new ServerIdleHandler();
    final RpcHandler rpcHandler = new RpcHandler(true, this.userProcessors);
    this.bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
        protected void initChannel(SocketChannel channel) throws Exception {
            ChannelPipeline pipeline = channel.pipeline();
            pipeline.addLast("decoder", new RpcProtocolDecoder(1));
            pipeline.addLast("encoder", new ProtocolCodeBasedEncoder(ProtocolCode.fromBytes(new byte[]{2})));
            if (idleSwitch) {
                pipeline.addLast("idleStateHandler", new IdleStateHandler(0L, 0L, (long)idleTime, TimeUnit.MILLISECONDS));
                pipeline.addLast("serverIdleHandler", serverIdleHandler);
            }

            pipeline.addLast("connectionEventHandler", RpcServer.this.connectionEventHandler);
            pipeline.addLast("handler", rpcHandler);
            this.createConnection(channel);
        }

        private void createConnection(SocketChannel channel) {
            Url url = RpcServer.this.addressParser.parse(RemotingUtil.parseRemoteAddress(channel));
            if (RpcServer.this.globalSwitch.isOn(2)) {
                RpcServer.this.connectionManager.add(new Connection(channel, url), url.getUniqueKey());
            } else {
                new Connection(channel, url);
            }

            channel.pipeline().fireUserEventTriggered(ConnectionEventType.CONNECT);
        }
    });
}
protected boolean doStart() throws InterruptedException {
    this.channelFuture = this.bootstrap.bind(new InetSocketAddress(this.port)).sync();
    return this.channelFuture.isSuccess();
}

(9)服务发布配置ProviderConfig实例绑定Provider配置发生变化监听器ProviderAttributeListener,监听Provider属性变化更新服务发布配置属性:

/**
 * Provider配置发生变化监听器
 */
private class ProviderAttributeListener implements ConfigListener {

    @Override
    public void configChanged(Map newValue) {
    }

    @Override
    public synchronized void attrUpdated(Map newValueMap) {
        String appName = providerConfig.getAppName();
        // 可以改变的配置 例如tag concurrents等
        Map<String, String> newValues = (Map<String, String>) newValueMap;
        Map<String, String> oldValues = new HashMap<String, String>();
        boolean reexport = false;
        try { // 检查是否有变化
              // 是否过滤map?
            for (Map.Entry<String, String> entry : newValues.entrySet()) {
                String newValue = entry.getValue();
                String oldValue = providerConfig.queryAttribute(entry.getKey());
                boolean changed = oldValue == null ? newValue != null : !oldValue.equals(newValue);
                if (changed) {
                    oldValues.put(entry.getKey(), oldValue);
                }
                reexport = reexport || changed;
            }
        } catch (Exception e) {
            LOGGER.errorWithApp(appName, "Catch exception when provider attribute compare", e);
            return;
        }

        // 需要重新发布
        if (reexport) {
            try {
                if (LOGGER.isInfoEnabled(appName)) {
                    LOGGER.infoWithApp(appName, "Reexport service {}", providerConfig.buildKey());
                }
                unExport();
                // change attrs
                for (Map.Entry<String, String> entry : newValues.entrySet()) {
                    providerConfig.updateAttribute(entry.getKey(), entry.getValue(), true);
                }
                export();
            } catch (Exception e) {
                LOGGER.errorWithApp(appName, "Catch exception when provider attribute changed", e);
                //rollback old attrs
                for (Map.Entry<String, String> entry : oldValues.entrySet()) {
                    providerConfig.updateAttribute(entry.getKey(), entry.getValue(), true);
                }
                export();
            }
        }

    }
}

(10)注册订阅服务列表,判断服务发布配置是否注册,根据服务发布注册中心配置列表遍历注册中心配置通过注册中心工厂获取注册中心实例并且初始化启动注册中心,注册服务发布配置到注册中心:

/**
 * 订阅服务列表
 */
protected void register() {
    if (providerConfig.isRegister()) {
        List<RegistryConfig> registryConfigs = providerConfig.getRegistry();
        if (registryConfigs != null) {
            for (RegistryConfig registryConfig : registryConfigs) {
                Registry registry = RegistryFactory.getRegistry(registryConfig);
                registry.init();
                registry.start();
                try {
                    registry.register(providerConfig);
                } catch (SofaRpcRuntimeException e) {
                    throw e;
                } catch (Throwable e) {
                    String appName = providerConfig.getAppName();
                    if (LOGGER.isWarnEnabled(appName)) {
                        LOGGER.warnWithApp(appName, "Catch exception when register to registry: "
                            + registryConfig.getId(), e);
                    }
                }
            }
        }
    }
}

(11)全局运行时上下文RpcRuntimeContext增加缓存ProviderConfig,缓存服务发布配置到EXPORTED_PROVIDER_CONFIGS集合。
解析总结
SOFARPC服务发布流程概括为SOFARPC服务需要创建服务运行容器配置ServerConfig,自定义设置基础配置并且通过配置文件加载服务端默认配置;创建服务发布配置ProviderConfig,自定义设置接口名称、接口实现类引用以及指定服务端配置;服务发布启动类ProviderBootstrap发布服务:构造请求调用器ProviderProxyInvoker(最底层调用过滤器执行链FilterChain),提前初始化注册中心,创建服务端Server包括启动业务线程池bizThreadPool 、创建BoltServerProcessor处理器,服务端Server注册服务提供者配置ProviderConfig、服务端调用实现ProviderProxyInvoker,服务端Server启动服务创建RpcServer,将BoltServerProcessor处理器缓存到userProcessors,初始化服务启动ServerBootstrap,根据userProcessors创建RpcHandler处理器添加到ChannelPipeline,创建RPC服务连接完成启动服务链路。RPC服务请求调用RpcHandler的channelRead()方法获取UserProcessor执行handlerRequest()方法查找服务调用器Invoker实施调用过滤器执行链FilterChain方法调用。

SOFARPC服务发布流程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,601评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,748评论 6 342
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,520评论 25 707
  • 本文参与#漫步青春#征文活动,作者:周欢,本人承诺,文章内容为原创,且未在其他平台发布。 可曾牵挂着几缕身影 像踏...
    Eccentric啊阅读 119评论 1 0
  • 目 录 ·青春巷 上 一 章 ·快三秒周昆 文 / 水木刅 故事简介 夏雪的心思 1. 黄俊、周昆轻轻推...
    清和青时阅读 406评论 5 7