The target
- Integrate using SOFA plug-in
- Soul gateway complete SOFA call source analysis
- conclusion
## Gateway integrates SOFA plugin
- pom
< the dependency > < groupId > com. Alipay. Sofa < / groupId > < artifactId > sofa xml-rpc -all < / artifactId > < version > 5.7.6 < / version > </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-client</artifactId> < version > 4.0.1 < / version > < / dependency > < the dependency > < groupId > org. Apache. The curator < / groupId > < artifactId > curator - framework < / artifactId > < version > 4.0.1 < / version > < / dependency > < the dependency > < the groupId > org. Apache. Curator < / groupId > < artifactId > curator - recipes < / artifactId > < version > 4.0.1 < / version > < / dependency > <dependency> <groupId>org.dromara</groupId> <artifactId>soul-spring-boot-starter-plugin-sofa</artifactId> <version>${soul-version}</version> </dependency>Copy the code
Business services access the Soul gateway
- pom
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-client-sofa</artifactId>
<version>${soul-version}</version>
</dependency>
Copy the code
- application.yml
soul:
sofa:
adminUrl: http://localhost:9095
contextPath: /sofa
appName: sofa
Copy the code
-
The interface is registered with the gateway
-
- The @soulsofaclient annotation on the method of your SOFA service implementation class indicates that the interface method is registered with the gateway.
-
- Start your provider and export logs
sofa client register success
Done, your SOFA interface has been published to the Soul Gateway. If there are still do not understand, you can refer tosoul-test-sofa
The project.
- Start your provider and export logs
@Service("sofaTestService") public class SofaTestServiceImpl implements DubboTestService { @Override @SoulSofaClient(path = "/findById", desc = "Find by Id") public DubboTest findById(final String id) { DubboTest dubboTest = new DubboTest(); dubboTest.setId(id); dubboTest.setName("hello world Soul Sofa, findById"); return dubboTest; } @Override @SoulSofaClient(path = "/findAll", desc = "Get all data") public DubboTest findAll() { DubboTest dubboTest = new DubboTest(); dubboTest.setName("hello world Soul Sofa , findAll"); dubboTest.setId(String.valueOf(new Random().nextInt())); return dubboTest; } @Override @SoulSofaClient(path = "/insert", desc = "Insert a row of data") public DubboTest insert(final DubboTest dubboTest) { dubboTest.setName("hello world Soul Sofa: " + dubboTest.getName()); return dubboTest; }}Copy the code
- Soul-admin Interface registration result
Soul-admin supports sofa plug-in
- First of all in
soul-admin
Plug-in management, thesofa
The plug-in is enabled. - Second in
sofa
Configure your registry address or the address of another registry in the plugin.
Soul gateway complete SOFA call source analysis
- SofaPluginConfiguration
@configuration @conditionalonclass (sofaplugin.class) public class SofaPluginConfiguration {/** * sofa plugin initialization */ @bean public SoulPlugin sofaPlugin(final ObjectProvider<SofaParamResolveService> sofaParamResolveService) { // Initialization SofaProxyService sofa service broker return new SofaPlugin (new SofaProxyService (sofaParamResolveService. GetIfAvailable ())); } @bean public SoulPlugin bodyParamPlugin() {return new bodyParamPlugin(); } @bean public SoulPlugin sofaResponsePlugin() {return new sofaResponsePlugin(); } /** * Sofa data processor plug-in initialization, */ @bean public PluginDataHandler() {return new sofaPluginDataHandler(); } /** * sofa metadata change subscription initialization */ @bean public MetaDataSubscriber sofaMetaDataSubscriber() {return new SofaMetaDataSubscriber(); }}Copy the code
- SofaPlugin
The following is the core code for SOFA request processing
@Override protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, Final RuleData rule) {// Retrieve data from request parameters String body = exchange.getAttribute(Constants.SOFA_PARAMS); // Get soul gateway CONTEXT SoulContext SoulContext = exchange.getAttribute(Constants.CONTEXT); assert soulContext ! = null; MetaData = exchange.getAttribute(Constants.META_DATA); If (! checkMetaData(metaData)) { assert metaData ! = null; log.error(" path is :{}, meta data have error.... {}", soulContext.getPath(), metaData.toString()); exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); Object error = SoulResultWrap.error(SoulResultEnum.META_DATA_ERROR.getCode(), SoulResultEnum.META_DATA_ERROR.getMsg(), null); return WebFluxResultUtils.result(exchange, error); } if (StringUtils.isNoneBlank(metaData.getParameterTypes()) && StringUtils.isBlank(body)) { exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); Object error = SoulResultWrap.error(SoulResultEnum.SOFA_HAVE_BODY_PARAM.getCode(), SoulResultEnum.SOFA_HAVE_BODY_PARAM.getMsg(), null); return WebFluxResultUtils.result(exchange, error); } / / by proxy call sofa interface final Mono < Object > result = sofaProxyService. GenericInvoker (body, metaData exchange); return result.then(chain.execute(exchange)); }Copy the code
- SofaProxyService
The following is the core processing of sofa remote call. It can be seen that similar to Dubbo, it is also a generalization call
public Mono<Object> genericInvoker(final String body, final MetaData metaData, Final ServerWebExchange Exchange) throws SoulException {// Obtain the generalization proxy reference ConsumerConfig<GenericService> reference = ApplicationConfigCache.getInstance().get(metaData.getPath()); if (Objects.isNull(reference) || StringUtils.isEmpty(reference.getInterfaceId())) { ApplicationConfigCache.getInstance().invalidate(metaData.getServiceName()); reference = ApplicationConfigCache.getInstance().initRef(metaData); } GenericService genericService = reference.refer(); Pair<String[], Object[]> pair; if (null == body || "".equals(body) || "{}".equals(body) || "null".equals(body)) { pair = new ImmutablePair<>(new String[]{}, new Object[]{}); } else { pair = sofaParamResolveService.buildParameter(body, metaData.getParameterTypes()); } CompletableFuture<Object> future = new CompletableFuture<>(); / / response callback RpcInvokeContext getContext () setResponseCallback (new SofaResponseCallback < Object > () {@ Override public void onAppResponse(final Object o, final String s, final RequestBase requestBase) { future.complete(o); } @Override public void onAppException(final Throwable throwable, final String s, final RequestBase requestBase) { future.completeExceptionally(throwable); } @Override public void onSofaException(final SofaRpcException e, final String s, final RequestBase requestBase) { future.completeExceptionally(e); }}); // GenericService. $invoke(metadata.getMethodName (), psion.getLeft (), psion.getright ())); // According to the callback, Return mono.fromFuture (future.thenapply (ret -> {if (objects.isnull (ret)) {ret = Constants.SOFA_RPC_RESULT_EMPTY; } exchange.getAttributes().put(Constants.SOFA_RPC_RESULT, ret); exchange.getAttributes().put(Constants.CLIENT_RESPONSE_RESULT_TYPE, ResultEnum.SUCCESS.getName()); return ret; })).onErrorMap(SoulException::new); }Copy the code
- SofaResponsePlugin
The following is the core code for handling sofa call response data
@Override public Mono<Void> execute(final ServerWebExchange exchange, Final SoulPluginChain chain) {return chain.execute(exchange).then(mono.defer (() -> {final Object result = exchange.getAttribute(Constants.SOFA_RPC_RESULT); if (Objects.isNull(result)) { Object error = SoulResultWrap.error(SoulResultEnum.SERVICE_RESULT_ERROR.getCode(), SoulResultEnum.SERVICE_RESULT_ERROR.getMsg(), null); return WebFluxResultUtils.result(exchange, error); } Object success = SoulResultWrap.success(SoulResultEnum.SUCCESS.getCode(), SoulResultEnum.SUCCESS.getMsg(), JsonUtils.removeClass(result)); / / handle return data return WebFluxResultUtils. Result (exchange, success); })); }Copy the code
-
review
At this point, the soul gateway support SOFA call source code processing process is probably completed analysis, specific processing details need to be further improved
conclusion
The soul-admin sofa plugin should be enabled and the soul-admin SOFA plugin should be configured with a registry. The soul-admin sofa plugin should be enabled and the soul-admin SOFA plugin should be configured. In the stage of source code analysis, it can be seen that the sofa processing process follows the responsibility chain mode to deal with the plug-in chain, which is similar to Dubbo in RPC call.