Six Appropriate Opening Ways of Spring Native Rpc Implementation

Posted by BigChief on Sun, 12 May 2019 09:43:28 +0200

Preface

When talking about Rpc in the Java ecosystem, many people may think of frameworks such as Dubbo, Motan, Grpc, etc. But you know what? Spring, as a Java programming family bucket, has built-in a variety of RPC implementations that can be used directly. Existence is reasonable. In some scenarios, heavy RPC components such as Dubbo and Grpc are not needed, so Spring's lightweight packaging can come in handy. Here's how to implement RPC in Spring and how to use it.

Code address: https://gitee.com/kailing/spring-rpc

What is Rpc?

Rpc (Remote Procedure Call): The remote invocation process encapsulated with internal implementation is rpc. RPC is mainly to simplify the remote service invocation. In general, it is to invoke the remote service (cross-host, cross-process) just like calling the local method. Fegin technology in Spring Cloud system can also be considered as a Rpc technology for data transmission using http protocol.

Rpc in Spring

Spring has built-in six native Rpc implementations of different data transmission modes, namely WebService, Jms, Rmi, Http, Hessian (http), Amqp. Familiar with Rpc knowledge, in Java, mainly through the generation of service interface proxy to achieve Rpc service invocation, Dubbo, Motan, Spring implementation is the same. In Rpc service invocation, there are two roles: service provider and invoker (consumer). On the one hand, the service caller transfers the service-defined interface name + method parameters to the provider through the proxy when the service is invoked. On the other hand, the service provider gets the interface information and finds the local service generation result and returns it to the caller. So the six Rpc implementations described below all have a common service interface definition and their respective proxy implementation configurations.

Define service interfaces

/**
 * @WebService Annotations are only used for RPC services provided by ws
 */
@WebService
public interface AccountService {
     
     Account getAccount(String name);
     
     class Account implements Serializable {
          private String name;
          public String getName(){
               return name;
          }
          public void setName(String name) {
               this.name = name;
          }
     }
}

A public api, which is used by both providers and consumers of Rpc, implements this interface to provide services, and consumers generate proxy implementations of this interface through proxy, then send specific messages through underlying encapsulation.Similar to using dubbo and motan

Call service code

@SpringBootApplication
public class WsConsumerApplication {

    @Autowired
    private AccountService accountService;

    @PostConstruct
    public void callRpcService(){
        System.out.println("RPC Remote Access Begins!");
        System.err.println(accountService.getAccount("kl").getName());
        System.out.println("RPC The remote access is over!");
    }

    public static void main(String[] args) {
        SpringApplication.run(WsConsumerApplication.class, args);
    }
}

Each Rpc implementation is the same, invoking services through proxy implementations injected into the AccountService interface. However, the configuration of each Rpc agent will be slightly different, mainly reflected in different transmission technologies will use different configurations. In general, the connection url( http://127.0.0.1 tcp://172.0.0.1, rmi://127.0.0.1, ports and proxy interface information are all common needs.

Implementation of Web Service with Rpc

Service Provider

Service realization

@WebService(serviceName="AccountService",endpointInterface = "com.spring.rpc.api.AccountService")
@Service
public class AccountServiceImpl  extends SpringBeanAutowiringSupport implements  AccountService {

    Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    @WebMethod
    public Account getAccount(String name) {
        logger.info("{} Ask for an account!", name);
        Account account = new Account();
        account.setName(name + "Account number");
        return account;
    }
}

Unlike other service implementations, Web Service defines services with @WebService and @WebMethod annotation Tags

Service exposure

@Configuration
public class WsConfig {
    private String ipList = "127.0.0.1";
    private String userName = "admin";
    private String passWord = "sasa";

    @Bean
    public SimpleHttpServerJaxWsServiceExporter rmiServiceExporter(Authenticator authenticator) {
        SimpleHttpServerJaxWsServiceExporter exporter = new SimpleHttpServerJaxWsServiceExporter();
        exporter.setHostname("127.0.0.1");
        exporter.setPort(8083);
        exporter.setAuthenticator(authenticator);
        return exporter;
    }
    @Bean
    public Authenticator authenticator(){
        Authenticator authenticator = new Authenticator();
        authenticator.setIpList(ipList);
        authenticator.setUserName(userName);
        authenticator.setPassWord(passWord);
        return authenticator;
    }
}

Complete the above code, in fact, we have built a complete Web Service service, and added user, password and ip whitelist interface authentication, access: http://127.0.0.1:8083/AccountServiceImpl?WSDL You can see the definition of a service as follows:

Service consumers

@Configuration
public class WsConfig {

    @Bean("accountService")
    public JaxWsPortProxyFactoryBean accountService()throws Exception{
        JaxWsPortProxyFactoryBean factoryBean = new JaxWsPortProxyFactoryBean();
        factoryBean.setServiceName("AccountService");
        factoryBean.setPortName("AccountServiceImplPort");
        factoryBean.setNamespaceUri("http://provider.ws.rpc.spring.com/");
        URL wsdlDocumentUrl = new URL("http://127.0.0.1:8083/AccountServiceImpl?WSDL");
        factoryBean.setWsdlDocumentUrl(wsdlDocumentUrl);
        factoryBean.setServiceInterface(AccountService.class);
        factoryBean.setUsername("admin");
        factoryBean.setPassword("sasa");
        return factoryBean;
    }
}

Obtain the proxy instance of AccountService.class by declaring the JaxWsPortProxyFactoryBean. When injecting a service invocation method, it actually triggers a remote invocation of a Web Service.

Rpc Implementation of Http

Service Provider

Service realization

@Service
public class AccountServiceImpl implements AccountService {

    Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public Account getAccount(String name) {
        logger.info("{} Ask for an account!", name);
        Account account = new Account();
        account.setName(name + "Account number");
        return account;
    }
}

Service exposure

@Configuration
public class HttpConfig {

    @Bean("/AccountService")
    public HttpInvokerServiceExporter rmiServiceExporter(AccountServiceImpl accountService){
        HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter();
        exporter.setService(accountService);
        exporter.setServiceInterface(AccountService.class);
        return exporter;
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean(DispatcherServlet dispatcherServlet) {
        ServletRegistrationBean servlet = new ServletRegistrationBean();
        servlet.setServlet(dispatcherServlet);
        servlet.setName("remoting");
        servlet.setLoadOnStartup(1);
        servlet.addUrlMappings("/remoting/*");
        return servlet;
    }
}

Service consumers

@Configuration
public class HttpConfig {

    @Bean("accountService")
    public HttpInvokerProxyFactoryBean accountService(){
        HttpInvokerProxyFactoryBean factoryBean = new HttpInvokerProxyFactoryBean();
        factoryBean.setHttpInvokerRequestExecutor(new HttpComponentsHttpInvokerRequestExecutor());
        factoryBean.setServiceUrl("http://127.0.0.1:8081/remoting/AccountService");
        factoryBean.setServiceInterface(AccountService.class);
        return factoryBean;
    }
}

As you can see, when configuring the Rpc service consumer implemented by Http, it is similar to Web Service. Defining a FactoryBean is ok ay. In fact, the other four Rpc implementations are similar. Not all of them are listed later.

Conclusion

When the blog was drafted, it was intended to describe in detail the six Rpc implementations built into Spring, and then look at them and see that they are really similar to each other. It's just that implementations like Amqp and Jms and Web Service need to be understood by people with technical experience in this area. However, the use and implementation of Rpc are almost the same, so there is no list of occupied space. But the six implementations mentioned above, WebService, Jms, Rmi, Http, Hessian and Amqp, all have detailed example programs in the git warehouse above. If you are interested in it, you may download it and run around to see how each implemented proxy factory class is implemented. It will help you really understand the calling process of Rpc and realize your own Rpc wheel.

Author's Profile:

Chen Kailing joined Kaijing Science and Technology in May 2016. He is currently the manager of the Architecture Group of the Operations and Maintenance Department of Kaijing Science and Technology Research Center. Independent Blog KL Blog( http://www.kailing.pub Blogger.

Welcome to Kaijing Open Source Technology QQ Cluster: 613025121, and share with us the technical architecture of Internet applications.

Topics: Java Spring Dubbo Programming