preface
To put it simply, architecture is a combination of technologies, frameworks and tools. As for how to combine, it will test the experience and level of architects. An excellent architecture can make the development efficiency more efficient and save more costs for enterprises. Programmers can focus more on the implementation of business requirements without being disturbed by the complex technical details at the bottom.
Architects (or people engaged in Architecture) are like explorers. They walk in front of the team and pave the way for everyone Road, leading you to find a shortcut to success. In addition, we should not copy other people's so-called best practices when doing architecture work. Instead, we should flexibly select and design the most reasonable architecture according to our own actual situation and local conditions. The purpose of the architecture is to make the business easier to implement, reduce the development cost and standardize the development. The responsibility of architects is to avoid people stepping on the pit. They need to sum up their own experience and lead them to the right path. Architects are not only experiencing the danger and happiness of exploration, but also settling down the experience accumulated by exploration, so that more people behind them can benefit from it.
With the surge of the Internet, the Internet industry has developed very rapidly. At this point, the centralized implementation of all businesses in one application can no longer meet the needs of the company and business development. Building a system based on service-oriented architecture has become the only choice for Internet architects to build a system, and one of the basic technologies for the implementation of service-oriented architecture is the distributed service framework.
RPC framework principle
RPC (remote procedure call) is generally used to call methods between systems deployed on different machines, so that programs can access remote system resources through network transmission like accessing local system resources. The architecture principle of RPC framework implementation is similar, as shown in the following figure.
In this architecture, the following aspects are the key points.
- Client Code: the client caller code implementation is responsible for initiating RPC calls and providing API for caller users.
- Serialization/Deserialization: it is responsible for serializing and deserializing the contents of RPC calls transmitted over the network. Different RPC frameworks have different implementation mechanisms. It is mainly divided into two categories: text and binary. The serialization mechanisms of text categories mainly include XML and JSON formats. The common serialization mechanisms of binary categories include Java Native serialization mechanism and hessian Protobuf, thrift Avro, Kryo, MessagePack, etc. Different serialization methods have great differences in readability, bitstream size, supported data types and performance. Users need to screen and screen according to their actual situation.
- Stub Proxy: can be regarded as a proxy object, shielding the complex network processing logic in the RPC call process, making the PRC call transparent and maintaining the same code style as the local call.
- Transport: as the communication transmission module at the bottom of the RPC framework, it generally transmits request and response messages between the client and the server through the Socket.
- ServerCode: the specific implementation of service business logic on the server side. The following sections introduce several commonly used RPC frameworks.
Introduction to RMI
Java RMI (remote method invocation) is a Java based remote method invocation technology. It is a unique RPC implementation of Java. It enables transparent communication and method calls between Java objects deployed on different hosts, as shown in the following figure.
RMI features are summarized below.
Support true object-oriented polymorphism. The full support of object orientation is also one of the advantages of RMI over other RPC frameworks.
- The Java language is unique and does not support other languages. It can perfectly support the unique features of the Java language.
- The Java Native serialization mechanism is used, and all serialized objects must implement java Io Serializable interface.
- The underlying communication is completed based on the Socket implemented by BIO (synchronous blocking I/O).
The performance of RMI is poor due to the performance problems of Java Native serialization mechanism and BIO communication mechanism This scheme is not recommended for use scenarios with high performance requirements.
Native RMI code example
Examples of RMI usage are as follows
Define RMI external service interface HelloService:
import java. rmi . Remote; import java. rmi . RemoteException; public interface HelloService extends Remote { String sayHello (String someOne) throws RemoteException; }
RMI interface method definitions must explicitly declare that RemoteException exceptions are thrown
The server interface implements HelloServicelmpl:
import java. rmi . RemoteException; import java. rmi . server .Unicas tRemoteobject; public class Hel loServiceImpl extends UnicastRemoteobject implements HelloService { private static final long serialVersionUID = -6190513770400890033L; public HelloServiceImpl () throws RemoteException { super() ; } @Override public String sayHe11o (String someOne) throws RemoteException { return "Hello," + someOne; }
The server-side method implementation must inherit the UnicastRemoteObject class, which defines the service caller and service provider object instances and establishes a one-to-one connection.
Server RMI service startup code:
import java . rmi . Naming; import java. rmi . registry . LocateRegistry; public class ServerMain { public static void main(String[] args) throws Exception { //Create service HelloService helloService = new HelloServiceImpl () ; //Registration service LocateRegistry . createRegistry(8801) ; Naming . bind ("rmi://localhost: 8801 /helloService", helloService) ; System. out.println ("ServerMain provide RPC service now") ; } }
Client remote call RMI service code:
import rmi . study . server . HelloService; import java. rmi .Naming; . public class ClientMain { public static void main (String[] args) throws Exception { //Service Introduction HelloService helloService = (HelloService) Naming. lookup ("rmi:// localhost : 8801/helloService") ; //Call remote method System. out. println ("RMI The result returned by the server is:"+ helloService .sayHello ("liyebing")); } }
First run the server program ServerMain, and then run ClientMain. The running results are as follows:
RMI The result returned by the server is: Hello, liyebing
RMI penetrates firewall
The communication port of RMI is generated randomly, so it may be blocked by firewall. To prevent being blocked by the firewall, the RMI communication port needs to be forcibly specified. It is generally implemented by customizing an RMISocketFactory class. The code is as follows:
import java. io. IOException; import java.net. ServerSocket; import java.net. Socket; import java. rmi . server . RMISocketFactory; public class Cus tomerSocketFactory extends RMISocketFactory { //Specify the communication port to prevent it from being blocked by the firewall @Override public Socket createSocket (String host, int port) throws IOException { return new Socket (host, port) ; } @Override public ServerSocket createServerSocket (int port) throws IOException { if (port == 0) { port = 8501; } System. out.println("rmi notify port:" + port) ; return new ServerSocket (port) ; } }
Then inject the newly defined class into Rmiserver. The code is as follows:
import java. rmi . Naming; import java. rmi . registry . LocateRegistry; import java. rmi . server . RMISocketFactory; public class ServiceMain { public static void main(String[] args) throws Exception{ LocateRegistry. createRegistry(8801) ; //Specify the communication port to prevent it from being blocked by the firewall RMISocketFactory . setSocketFactory (new Custome rSocketFactory()) ; HelloService helloService = new HelloServiceImpl () ; Naming.bind ("rmi://localhost: 8801/helloService" , helloService) ; System. out.println ("ServiceMain provide RPC service now.") ; } }
CXF/Axis2 introduction
WebService is a cross platform RPC technical protocol. The WebService technology stack consists of SOAP(SampleObject Access Protocol), UDDI (Universal Description, discovery and integration) and WSDL (Web service description language). Among them, SOAP is a communication protocol that uses XML to encode data. It is independent of platform and language. It is simple and extensible. Because SOAP transmits data based on HTTP protocol, it can bypass the firewall. SOAP provides a standard way for applications running on different operating systems and using different technologies and programming languages to communicate with each other. UDDI is a platform independent framework and a universal description, discovery and integration service. WSDL is a web service description language written in XML, which is used to describe WebService and how to access WebService.
The following describes two WebServic implementations commonly used in Java development: CXF and Axis2
CXF introduction
Apache CXF is an open source WebService RPC framework. It is the result of the merger of two famous open source projects, ObjectWebCeltix and CodehausXFire. ApacheCXF contains a wide range of fully functional collections. It mainly has the following characteristics.
- Support Web Services standards, including SOAP (SOAP1.1 and SOAP1.2) specifications, WSI BasicProfile, WSDL, WS- Addressing, WS policy, WS reliablemessaging, WS security, etc.
- Support JSR related specifications and standards, including jax-ws (Java API for XML based web.Services2.0), jax-rs (the Java API for restful web services), saaj (soap withattachments API for Java).
- Support multiple transport protocols, protocol binding and data binding.
- Protocol binding: SOAP, REST/HTTP, XML.
- Data binding: JAXB 2 10. Aegis, Apache XMLBeans, etc.
The usage of CXF is illustrated by a JavaWeb project integrating Spring Maven. For the convenience of demonstration, the server and client of WebService are written into a project. The structure of the project is as follows.
The key code of the CXF integration SpringMaven project example is described below.
Define the service interface HelloService, where the interface is marked as a WebService remote service interface with the annotation @webservice:
package Cxf .service; import javax. jws . WebService; @WebService public interface HelloService { public String sayHello (String content) ; package Cxf .service; import javax. jws . WebService; @WebService (endpointInterface = "Cxf . service. HelloService") public class HelloServiceImpl implements HelloService { public String sayHe11o (String content) { return "hello," + content; } }
In the above code, the implementation class of the WebService service interface is HelloServicelmpl. At the same time, the annotation @webservice is used, and the corresponding interface implementation CXF is indicated through the endpointInterface Service Helloservice.
CXF server The main contents of the XML configuration are as follows:
<import resource="classpath :META- INF/cxf/cxf.xml"/> <import resource="classpath :META-INE/cxf/cxf-servlet .xml"/> <j axws :endpoint id="hel loWorld" impl ementor="cxf . service . HelloServiceImpl" address=" /HelloWorld"/>
Web The XML configuration is as follows:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns :xsi="http:/ /www. w3. org/2001/XMLSchema- instance" xmlns="http:/ /java. sun. com/ xml /ns/ javaee" xsi : schemaLocation="http:/ /java. sun. com/ xml/ns/javaee http://java. sun. com/ xml/ns/javaee/web-app_ _2_ 5. xsd" id="WebApp_ ID" version="2.5"> <display-name>cxf-spring</display-name> <context-param> <param-name>contextConf igLocat ion</ param-name> <param-value>classpath: cxf-server .xml</param-value> </context-param> <listener> <listener-class> org. spr ingf ramework . web. context . ContextLoaderListener </ 1 istener-class> </listener> <servlet> <servlet-name>CXFServlet</ servlet-name> <servlet-class>org. apache . cxf. transport. servlet . CXFServlet</servlet- -class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</ servlet-name> <url-pattern>/ws/ *</url-pattern> </ servlet-mapping> </ web-app>
Pom The XML Maven dependency configuration is as follows:
<modelVersion>4.0.0</modelVersion> <groupId>cxf-spr ing-study</groupId> <artifactId>cxf-spring</artifactId> <version>1.0- SNAPSHOT</version> <packaging>war</packaging> <properties> <cxf. version>3.1.7</cxf. version> <spring. version>4.0.9. RELEASE</ spring . version> </properties> <dependencies> <dependency> <groupId>org . spring f ramework</groupId> <arti factId>spring-context</arti factId> <version>$ {spring. version}</version> </ dependency> <dependency> <groupId>org . spr ingframework</groupId> <artifactId>spr ing-webmvc</arti factId> <version>$ { spring. version}</version> </dependency> <dependency> <groupId>org . springf ramework</ groupId> <artifactId>spr ing-context-support</artifactId> <version>$ { spring. version}</version> </ dependency> <dependency> <groupId>org . apache .cxf</groupId> <arti factId>cxf-rt- frontend-jaxws</arti factId> <version>$ {cxf. version}</version> </dependency> <dependency> <groupId>org . apache. cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf. version}</version> </dependency> <dependency> <groupId>org .apache .cxf</groupId> <arti factId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf. version}</version> </ dependency> </dependencies>
Deploy and run in the Tomcat Web container, and the results are shown in the following figure.
Deploy and run in Tomcat
Then run localhost:8080/ws/HelloWorld?wsdl, get the results shown in the figure below, indicating that the WebService server-side service is published.
CXF WebService service publishing WSDL file
The following describes how the client invokes the WebService service published by the server.
First, configure the service import information CXF client XML, the main content is as follows:
<jaxws:client id="helloClient" serviceClass="cxf . service . HelloService" address="http://localhost : 8080/ws/HelloWorld" /> </beans>
serviceClass configures the WebService service interface published by the server, and address is the HTTP address for the service access of the server (WebService uses HTTP protocol for communication).
Finally, write the client call class CxfClient:
package cxf.client; import cxf . service. HelloService; import org. springframework. context . ApplicationContext; import org. springf ramework. context . support .ClassPathXmlApplicationContext; public class CxfClient { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlAppl icationContext ("classpath:cxf-client.xml") ; HelloService client = (HelloService) context. getBean ("helloClient") ; System. out .println (client . sayHel1o ("liyebing")) ; } }
The operation results are as follows
hello, liyebing
Axis2 introduction
Apache Axis2 is a subsequent version of axis. It is a new generation of SOAP engine. It is another very popular Web Services/SOAP/WSDL implementation besides CXF, and there are both Java and C language implementations. Here is an introduction to the implementation of Java language.
Axis2 mainly has the following features.
- High performance: Axis2 has its own lightweight object model AXIOM, and adopts Stax (streaming apifor XML) technology, which has better performance than axis1 X has lower memory consumption.
- Hot deployment: Axis2 is equipped with the ability to deploy Web services and handlers at system startup and runtime. In other words, you can add new services to the system without shutting down the server. Just archive and store the required Web service in the services directory of the repository, and the deployment model will automatically deploy the service and make it available for Use
- Asynchronous service support: Axis2 supports asynchrony using non blocking clients and transports, as well as Web services and asynchronous Web service invocation.
- WSDL support: Axis2 supports Web services description language versions 1.1 and 2.0, which allows you to easily build stubs to access remote services, and automatically export machine-readable descriptions of deployed services from Axis2.
The usage of Axis2 is illustrated by an integrated Spring Maven based JavaWeb project. For the convenience of demonstration, the server and client code of WebService are written into a project. The structure of the project is shown in the following figure
The key code of Axis2WebService server is as follows.
Define the WebService service interface:
package axis2. service; public interface HelloService { public String sayHello(String content) ; }
Service interface HelloService implementation:
package axis2. service; public class HelloServiceImpl implements HelloService { public String sayHello (String content) { return "hello," + content; }
Configuration file Axis2 server XML is used to declare Spring service Bean instances:
<bean id="hel loService" class="axis2. service . HelloServiceImpl"/>
Configuration file services XML is used to describe Axis2 services:
<serviceGroup> <service name="HelloService"> <description>Spring POJO Axis2 example</description> <parameter name="ServiceClass"> axis2. service. HelloService </pa rameter> <parameter name="Service0bjectSupplier"> org.apache .axis2. extensions. spring . receivers. SpringServletContextobjectSupplier </parameter> <parameter name="Spr ingBeanName">helloService</ parameter> <messageReceivers> <messageReceiver mep="http:/ /www.w3. org/2004/08/wsdl/ in-out" class="org. apache .axis2. rpc. receivers . RPCMessageReceiver" /> </messageReceivers> </ service> </ serviceGroup>
Where web The XML contents are as follows:
<?xml version="1. 0" encoding="UTF-8"?> <web-app xmlns:xsi="http:/ /www. w3. org/2001/XMLSchema- instance" xmlns="http:/ /java. sun. com/ xml /ns/javaee" xsi : schemaLocation="http://java. sun. com/ xml/ns/javaee http://java . sun. com/ xml/ ns/javaee/web-app_ _2_ _5.xsd" id="WebApp_ ID" version="2.5"> <display-name>axis2-spring</display-name> <context-param> <par am-name>contextConf igLocation</param-name> <param-value>classpath :axis2-server . xml</param-value> </context-param> <1 istener> <1 istener-class> org. spr ingf ramework. web. context . ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>Axi sServlet</ servlet-name> <servlet-class>org . apache . axis2. transport .http . AxisServlet</servlet-class> <load-on-startup>1</ load-on-startup> </servlet> <servlet -mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> </ web-app>
Configuration file pom Xmlmaven depends on the following:
<modelVersion>4.0. 0< /modelVersion> <groupId>axis2-spr ing- study</groupId> <arti factId>axis2-spring</arti factId> <version>1.0-SNAPSH0T</version> <packaging>war</packaging> <properties> <axis2. version>1.7.4</axis2. version> <spring. version>4.0.9. RELEASE</ spring. version> </properties> <dependencies> <!-- spring --> <dependency> <groupId>org . spr ingf ramework</groupId> <arti factId>spring-context</arti factId> <version>$ {spring. version}</version> </ dependency> <dependency> <groupId>org . springframework</groupId> <arti factId>spring-web</arti factId> <version>$ {spring. version}</version> </ dependency> <dependency> <groupId>org . springframework</groupId> <arti factId>spr ing-context-support</arti factId> <vers ion>$ {spring. version}</version> </ dependency> <!-- axis2 --> <dependency> <groupId>org . apache . axis2</groupId> <arti factId>axis2-transport-xmpp</arti factId> <version>$ { axis2. version}</version> </dependency> <dependency> <groupId>org. . apache . axis2</groupId> <arti factId>axis2-transport-udp</arti factId> <version>${axis2. version}</version> </ dependency> <dependency> <groupId>org. apache. axis2</groupId> <arti factId>axis2-transport-tcp</arti factId> <version>$ { axis2. version}</version> </dependency> <dependency> <groupId>org. apache. axis2</groupId> <arti factId>axis2-webapp</arti factId> <version>$ {axis2. version}</version> </dependency> <dependency> <groupId>org. apache.axis2</groupId> <arti factId>axis2 -xmlbeans</arti factId> <version>$ {axis2. version}</version> </dependency> <dependency> <groupId>org. apache. axis2</groupId> <arti factId>axis2-spring</arti factId> <version>${axis2. version}</version> </dependency> <dependency> <groupId>org . apache. axis2</groupId> <arti factId>axi s2- soapmonitor-servlet</arti factId> <version>${axis2. version}</version> </ dependency> </dependencies>
Deploy and run in Tomcat, and then run in the browser htp://ocalhos:8080/services/HelloService?wsdl , as shown in the following figure, it indicates that the WebService server is published.
There are many ways to call Axis2 clients. The following describes a dynamic calling method without pre generated code.
import org. apache . axis2. addressing . EndpointReference; import org. apache . axis2. client .Options; import org. apache .axis2. rpc .client. RPCServiceClient; . import org. apache .axis2. transport . http. HTTPConstants; import javax . xml .namespace . QName ; . public class Axis2Client { public static void main(String[] args) { try { EndpointReference targetEPR = new EndpointReference ( "http://localhost: 8080/services/HelloService") ; RPCServiceClient serviceClient = new RPCServiceClient() ; Options options = serviceCl ient . getOptions() ; options . setManageSession(true) ; options .setProperty (HTTPConstants. REUSE_ HTTP_ CLIENT, true) ; options .setTo (targetEPR) ; QName opQName = new QName ("http://service. axis2", "sayHello") ; //Set call parameters object[] paramArgs = new object[] {"liyebing"}; //Process return data Class[] returnTypes = new Class[] {String.class}; object[] response = serviceClient. invokeBlocking (opQName, paramArgs, returnTypes) ; serviceCl ient . cleanupTransport () ; String result = (String) response[0] ; if (result == null) { System. out . println ("HelloService didn't initialize!") ; } else { Sys tem. out .println (result) ; } } catch (Exception e) { e.printStackTrace() ; } } }
The operation results are as follows:
hello, liyebing
summary
This article mainly introduces the common RPC frameworks used in daily development, including RMI, CXF, Axis2,, and gives practical code examples for each RPC framework, as well as a simple RPC framework implemented by ourselves.