preface

The previous article briefly introduced the functions and features of SOFA-Boot and illustrated the configuration of Readiness health check. This paper mainly introduces how to introduce SOFA-RPC middleware in SOFA-Boot, and gives the whole process of service release and consumption based on bolt, REST and Dubbo.

This article will further introduce the rich and powerful functions provided by SOFA-RPC middleware, including one-way call, synchronous call, Future call, callback, generalization call, filter configuration, etc.

Other articles

  • Ant Financial RPC framework SOFA- INITIAL RPC experience

  • Ant Financial SOFA-Boot Integration SOFA-RPC

  • Ant Financial SOFA-Boot Integration SOFA-RPC

  • Ant Financial SOFA-Boot Integration SOFA-RPC

The body of the

1. Call method

SOFA-RPC provides four call mechanisms: one-way call, synchronous call, asynchronous call and callback. In order to distinguish the differences between the four, here is the schematic diagram provided by SOFA official.

Details and configuration instructions are as follows:

1.1. One-way mode

After the current thread initiates the call, it does not care about the call result, does not do timeout control, as long as the request has been issued, the call will be completed. Bolt protocol is currently supported.

Configuration instructions

To use one-way mode, you need to declare the call mode oneway with sofa:global-attrs element’s type attribute at the time of the service reference, so that one-way mode is used when invoking the service reference.

<sofa:reference id="helloOneWayServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloOneWayService">
    <sofa:binding.bolt>
        <sofa:global-attrs type="oneway"/>
    </sofa:binding.bolt>
</sofa:reference>
Copy the code

Applicable scenario

One-way calls do not guarantee success, and the initiator has no way of knowing the result of the call. Therefore, it is usually used in the scenario of retry or periodic notification. The invocation process may fail due to network problems or machine faults. Service scenarios can be used only when they accept such exception scenarios.

1.2. Synchronization mode

After the current thread initiates the call, wait for the response result within the specified timeout period to complete the call. If no result is returned within the timeout, a timeout exception is thrown.

Configuration instructions

Service interfaces and implementation classes

SOFA-RPC uses synchronous call by default and can omit SOFA :global-attrs configuration item.

The server publishes the configuration

<bean id="helloSyncServiceImpl" class="com.ostenant.sofa.rpc.example.invoke.HelloSyncServiceImpl"/>
<sofa:service ref="helloSyncServiceImpl" interface="com.ostenant.sofa.rpc.example.invoke.HelloSyncService">
    <sofa:binding.bolt/>
</sofa:service>
Copy the code

Client reference configuration

<sofa:reference id="helloSyncServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloSyncService">
    <sofa:binding.bolt/>
</sofa:reference>
Copy the code

Server startup entry

SpringApplication springApplication = new SpringApplication(SyncServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

Client startup entry

SpringApplication springApplication = new SpringApplication(SyncClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

Client call

HelloSyncService helloSyncServiceReference = (HelloSyncService) applicationContext.getBean("helloSyncServiceReference");
System.out.println(helloSyncServiceReference.saySync("sync"));
Copy the code

Applicable scenario

Synchronous invocation is the most common approach. Set the timeout period appropriately based on the peer processing capability.

1.3. The way of the Future

In the Future mode, the client does not wait for the result of the server after invoking and continues to execute the subsequent service logic. The result returned by the server is cached by SOFA-RPC. When the client needs the result, it needs to obtain it actively. Bolt protocol is currently supported.

Configuration instructions

Service interfaces and implementation classes

HelloFutureService.java

public interface HelloFutureService {
    String sayFuture(String future);
}
Copy the code

HelloFutureServiceImpl.java

public class HelloFutureServiceImpl implements HelloFutureService {
    @Override
    public String sayFuture(String future) {
        returnfuture; }}Copy the code

The server publishes the configuration

<bean id="helloFutureServiceImpl" class="com.ostenant.sofa.rpc.example.invoke.HelloFutureServiceImpl"/>
<sofa:service ref="helloFutureServiceImpl" interface="com.ostenant.sofa.rpc.example.invoke.HelloFutureService">
    <sofa:binding.bolt/>
</sofa:service>
Copy the code

Client reference configuration

To use the Future method, you need to declare the Future method when the service is referenced via the TYPE attribute of the SOFA :global-attrs element.

<sofa:reference id="helloFutureServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloFutureService">
    <sofa:binding.bolt>
        <sofa:global-attrs type="future"/>
    </sofa:binding.bolt>
</sofa:reference>
Copy the code

This is the Future approach used when invoking the service reference.

Server startup entry

SpringApplication springApplication = new SpringApplication(FutureServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

Client startup entry

SpringApplication springApplication = new SpringApplication(FutureClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

The client can obtain the returned result in two ways:

  • One, throughSofaResponseFutureGet the results directly. The first parameter is the timeout to get the result, and the second parameter indicates whether the result in the thread context is cleared.
HelloFutureService helloFutureServiceReference = (HelloFutureService) applicationContext
    .getBean("helloFutureServiceReference");
helloFutureServiceReference.sayFuture("future");

try {
    String result = (String)SofaResponseFuture.getResponse(1000.true);
    System.out.println("Future result: " + result)
} catch (InterruptedException e) {
    e.printStackTrace();
}
Copy the code
  • Second, get the native Future. This method takes the JDK’s native Future, and the argument indicates whether to clear the result in the thread context. The way you get the result is the way you get the JDK Future.
HelloFutureService helloFutureServiceReference = (HelloFutureService) applicationContext
    .getBean("helloFutureServiceReference");
helloFutureServiceReference.sayFuture("future");

try {
    Future future = SofaResponseFuture.getFuture(true);
    String result = (String)future.get(1000, TimeUnit.MILLISECONDS);
    System.out.println("Future result: " + result)
} catch (InterruptedException e) {
    e.printStackTrace();
}
Copy the code

Applicable scenario

The Future approach applies to non-blocking programming patterns. After the client program is processed, it is not necessary to obtain the return result immediately. Instead, the subsequent program code execution can be completed first, and the call return result can be actively obtained from the current thread context in subsequent services. Reduces the blocking and latency of code execution caused by network IO waits.

1.4. Callback mode

If the current thread initiates the call, the call ends immediately and the next call can be executed immediately. To initiate the call, you need to register a callback that allocates an asynchronous thread pool. When the response returns, the callback logic is executed in the callback’s asynchronous thread pool.

Configuration instructions

Service interfaces and implementation classes

HelloCallbackService.java

public interface HelloCallbackService {
    String sayCallback(String callback);
}
Copy the code

HelloCallbackServiceImpl.java

public class HelloCallbackServiceImpl implements HelloCallbackService {
    @Override
    public String sayCallback(String string) {
        returnstring; }}Copy the code

Business callback class

The client callback class needs to implement com. Alipay. Sofa. RPC. Core. Invoke. SofaResponseCallback interface.

CallbackImpl.java

public class CallbackImpl implements SofaResponseCallback {
    @Override
    public void onAppResponse(Object appResponse, String methodName, RequestBase request) {
        System.out.println("callback client process:" + appResponse);
    }

    @Override
    public void onAppException(Throwable throwable, String methodName, RequestBase request) {}@Override
    public void onSofaException(SofaRpcException sofaException, String methodName, RequestBase request) {}}Copy the code

The SofaResponseCallback interface provides three methods:

  • OnAppResponse: Enter this callback method if the program is running properly.
  • OnAppException: The callback method is entered when the server program throws an exception.
  • OnSofaException: The callback method is entered when an error occurs within the framework.

The server publishes the configuration

<bean id="helloCallbackServiceImpl" class="helloFutureServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloCallbackServiceImpl"/>
<sofa:service ref="helloCallbackServiceImpl" interface="helloFutureServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloCallbackService">
    <sofa:binding.bolt/>
</sofa:service>
Copy the code

Client reference configuration

The type attribute of the SOFA :global-attrs element is used to declare a callback when the service is referenced. Callback-ref is used to declare the implementation class of the callback.

<bean id="callbackImpl" class="com.ostenant.sofa.rpc.example.invoke.CallbackImpl"/>
<sofa:reference id="helloCallbackServiceReference"
                interface="com.ostenant.sofa.rpc.example.invoke.HelloCallbackService">
    <sofa:binding.bolt>
        <sofa:global-attrs type="callback" callback-ref="callbackImpl"/>
    </sofa:binding.bolt>
</sofa:reference>
Copy the code

This is the callback method used when invoking the service reference. When the result is returned, the corresponding method of the callback class is automatically called by SOFA-RPC.

Server startup entry

SpringApplication springApplication = new SpringApplication(CallbackServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

Client startup entry

SpringApplication springApplication = new SpringApplication(CallbackClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

The client initiates the call

HelloCallbackService helloCallbackServiceReference = (HelloCallbackService) applicationContext
            .getBean("helloCallbackServiceReference");
helloCallbackServiceReference.sayCallback("callback");

try {
    Thread.sleep(3000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
Copy the code

The return value of sayCallback() should not be fetched directly. In a callback class registered with the client, the return value is passed in as an argument to the correct method, which is then called back to complete the subsequent logical processing.

Applicable scenario

The Callback approach works well with asynchronous non-blocking programming patterns. The thread of the client program initiates the call and continues to perform subsequent operations without actively fetching the return value. The server program completes processing and returns the return value to an asynchronous thread pool, where the child threads handle the return value via the callback function. Greatly reduce network IO blocking, solve the bottleneck of single thread, realize asynchronous programming.

2. Generalization calls

The generic invocation method, which can be invoked by the client without relying on the server’s interface, currently supports bolt. We do not know the interface of the server, so we need to describe the interface of the server, the method called, the parameter, and the result class in a string.

Configuration instructions

Generalization parameter class

SampleGenericParamModel.java

public class SampleGenericParamModel {
    private String name;
    public String getName(a) {
        return name;
    }
    public void setName(String name) {
        this.name = name; }}Copy the code

The generalization returns the class

SampleGenericResultModel.java

public class SampleGenericResultModel {
    private String name;
    private String value;
    public String getName(a) {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getValue(a) {
        return value;
    }
    public void setValue(String value) {
        this.value = value; }}Copy the code

Service interfaces and implementation classes

SampleGenericService.java

public interface SampleGenericService {
    SampleGenericResultModel sayGeneric(SampleGenericParamModel sampleGenericParamModel);
}
Copy the code
  • SampleGenericParamModel: As the input parameter type of sayGeneric(), there is a name member variable, which is the actual method entry parameter.

  • SampleGenericResultModel: As the return type of sayGeneric(), the name and value member variables are declared as the actual return values.

SampleGenericServiceImpl.java

public class SampleGenericServiceImpl implements SampleGenericService {
    @Override
    public SampleGenericResultModel sayGeneric(SampleGenericParamModel sampleGenericParamModel) {
        String name = sampleGenericParamModel.getName();
        SampleGenericResultModel resultModel = new SampleGenericResultModel();
        resultModel.setName(name);
        resultModel.setValue("sample generic value");
        returnresultModel; }}Copy the code

The server publishes the configuration

<bean id="sampleGenericServiceImpl" class="com.ostenant.sofa.rpc.example.generic.SampleGenericServiceImpl"/>
<sofa:service ref="sampleGenericServiceImpl" interface="com.ostenant.sofa.rpc.example.generic.SampleGenericService">
    <sofa:binding.bolt/>
</sofa:service>
Copy the code

Client reference configuration

<sofa:reference id="sampleGenericServiceReference" interface="com.alipay.sofa.rpc.api.GenericService">
    <sofa:binding.bolt>
        <sofa:global-attrs generic-interface="com.ostenant.sofa.rpc.example.generic.SampleGenericService"/>
    </sofa:binding.bolt>
</sofa:reference>
Copy the code

There are two things to note about the client configuration during the generalization call:

  • sofa:referenceThe service interface pointed to needs to declare the generic interface provided for SOFA-RPCcom.alipay.sofa.rpc.api.GenericService.
  • sofa:global-attrsYou need to declare propertiesgeneric-interfaceValue indicates the actual service interface name.

Server startup entry

SpringApplication springApplication = new SpringApplication(SampleGenericServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

Client startup entry

SpringApplication springApplication = new SpringApplication(SampleGenericClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

The client initiates the call

  • Gets a generalized reference to the service
GenericService sampleGenericServiceReference = (GenericService) applicationContext
    .getBean("sampleGenericServiceReference");
Copy the code
  • Preparation Method Parameters

Because the client does not have to invoke the service parameters, so by com. Alipay. The hessian. Generic. Model. GenericObjectGenericObject is described.

// Prepare method parameters
GenericObject genericParam = new GenericObject(
    "com.ostenant.sofa.rpc.example.generic.SampleGenericParamModel");
genericParam.putField("name"."Harrison");
Copy the code

GenericObject holds a variable of type Map

. You can describe a parameter class by putting its attributes and values into the Map via the putField() method provided by GenericObject.
,>

  • Initiate a generalization call

The $genericInvoke(arg1, AGR2, arg3) method of GenericService can initiate a generalized call to the service. The parameters are as follows:

parameter meaning Parameters can be chosen
arg1 Target method name mandatory
arg2 An array of parameter types, in strict order mandatory
arg3 An array of parameter values that must be consistent with the array of parameter types mandatory
arg4 The Class type of the return value optional

A:

GenericObject genericResult = (GenericObject) sampleGenericServiceReference.$genericInvoke(
    // Target method name
    "sayGeneric".// Parameter type name
    new String[] { "com.ostenant.sofa.rpc.example.generic.SampleGenericParamModel" },
    // The value of the parameter
    new Object[] { genericParam });

// Verify the return result
System.out.println("Type: " + genericResult.getType());
System.out.println("Name: " + genericResult.getField("name"));
System.out.println("Value: " + genericResult.getField("value"));
Copy the code

Method 2:

SampleGenericResultModel sampleGenericResult = sampleGenericServiceReference.$genericInvoke(
    // Target method name
    "sayGeneric".// Parameter type name
    new String[] { "com.ostenant.sofa.rpc.example.generic.SampleGenericParamModel" },
    // The value of the parameter
    new Object[] { genericParam },
    // Return the Class type of the value
    SampleGenericResultModel.class);

// Verify the return result
System.out.println("Type: " + sampleGenericResult.getClass().getName());
System.out.println("Name: " + sampleGenericResult.getName());
System.out.println("Value: " + sampleGenericResult.getValue());
Copy the code

View console output

The two output modes are as follows:

Type: com.ostenant.sofa.rpc.example.generic.SampleGenericResultModel
Name: Harrison
Value: sample generic value
Copy the code

3. Configure filters

SOFA-RPC intercepts request and response through Filter. Users can customize Filter to achieve interception extension, currently supports bolt protocol. Developers through inheritance com. Alipay. Sofa. RPC. Filter. The filter implement custom filters.

Configuration instructions

Service interfaces and implementation classes

FilterService.java

public interface FilterService {
    String sayFilter(String filter);
}
Copy the code

FilterServiceImpl.java

public class FilterServiceImpl implements FilterService {
    @Override
    public String sayFilter(String filter) {
        returnfilters; }}Copy the code

Server filter

In the Filter implementation class, the invoke() method implements concrete interception logic. Filterinvoker.invoke (SofaRequest) triggers the invocation of the service, and concrete interception processing can be implemented before and after the method.

public class SampleServerFilter extends Filter {
    @Override
    public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
        System.out.println("SampleFilter before server process");
        try {
            return invoker.invoke(request);
        } finally {
            System.out.println("SampleFilter after server process"); }}}Copy the code

The server publishes the configuration

The server needs to configure the service implementation class and filter, and then configure the filter attribute on the SOFA :global-attrs tag of sofa: Service to bind the two.

<bean id="sampleFilter" class="com.ostenant.sofa.rpc.example.filter.SampleServerFilter"/>
<bean id="filterService" class="com.ostenant.sofa.rpc.example.filter.FilterServiceImpl"/>
<sofa:service ref="filterService" interface="com.ostenant.sofa.rpc.example.filter.FilterService">
    <sofa:binding.bolt>
        <sofa:global-attrs filter="sampleFilter"/>
    </sofa:binding.bolt>
</sofa:service>
Copy the code

Client-side filter

public class SampleClientFilter extends Filter {
    @Override
    public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
        System.out.println("SampleFilter before client invoke");
        try {
            return invoker.invoke(request);
        } finally {
            System.out.println("SampleFilter after client invoke"); }}}Copy the code

Client reference configuration

Similarly, the client filter needs to be configured with the filter attribute in sofa:global-attrs tag of SOFA: Reference to implement invocation interception of the client reference class.

<bean id="sampleFilter" class="com.alipay.sofa.rpc.samples.filter.SampleClientFilter"/>
<sofa:reference id="filterServiceReference" interface="com.ostenant.sofa.rpc.example.filter.FilterService">
    <sofa:binding.bolt>
        <sofa:global-attrs filter="sampleFilter"/>
    </sofa:binding.bolt>
</sofa:reference>
Copy the code

The server startup class

SpringApplication springApplication = new SpringApplication(FilterServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

Client startup class

SpringApplication springApplication = new SpringApplication(FilterClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Copy the code

Client call

FilterService filterServiceReference = (FilterService) applicationContext.getBean("filterServiceReference");
try {
    // Sleep 5s, easy to observe filter effect
    Thread.sleep(5000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

String result = filterServiceReference.sayFilter("filter");
System.out.println("Invoke result: " + result);
Copy the code

View interception output

  • The server prints the output
SampleFilter before server process
SampleFilter after server process
Copy the code
  • The client prints the output
SampleFilter before client invoke
SampleFilter after client invoke
Invoke result: filter
Copy the code

Filter configuration takes effect. The sequence of filter interception is as follows:

  1. The client initiates the call -> client front-end interception -> server front-end interception
  2. Server-side method execution
  3. Server backend interception -> client backend interception -> client receives the return value

summary

This paper introduces the centralized call mode of SOFA-RPC, including one-way call, synchronous call, Future call and callback, introduces the unique generalization call mechanism of SOFA-RPC, and briefly introduces the configuration of filter.


Welcome to pay attention to the technical public number: Zero one Technology Stack

This account will continue to share learning materials and articles on back-end technologies, including virtual machine basics, multithreaded programming, high-performance frameworks, asynchronous, caching and messaging middleware, distributed and microservices, architecture learning and progression.