preface
Architecture is simply a combination of technologies, frameworks and tools. As for how to combine them, it is a great test of the experience and level of the architect. An excellent architecture can make development efficiency more efficient and save more costs for enterprises. Programmers can focus more on the implementation of business requirements without being distracted by complex technical details at the bottom.
Architects (or people who work on them) are explorers who go in front of the team and lay the groundwork for everyone. Road, lead you to find a shortcut to success. In addition, when doing architecture work, we should not copy the so-called best practices of others. Instead, we should flexibly choose and design the most reasonable architecture according to our actual situation and local conditions. The purpose of architecture is to make business easier to land, reduce development costs and standardize development. It’s the architect’s job to keep people from stumbling, to take their own experience and lead them in the right direction. The architect is not only experiencing the dangers and joys of adventure, but is depositing the experience of exploration for the benefit of more people later on.
With the rising tide of Internet, the Development of the Internet industry is very rapid. At this point, the centralized implementation of all businesses in one application can no longer meet the needs of the company and business development. It has become the best choice for Internet architects to build systems based on service-oriented architecture (SOA), and distributed service framework is one of the basic technologies that SOA can land on.
Principle of RPC framework
Remote Procedure Call (RPC) is generally used to implement method calls between systems deployed on different machines, enabling programs to access Remote system resources over the network just as they access local system resources. The architectural principles of RPC framework implementations are similar, as shown in the figure below.
Within this architecture, the following aspects are key.
- Client Code: the Code implementation of the Client caller, which is responsible for initiating RPC calls and providing apis for the caller user.
- Serialization/Deserialization: responsible for the content of the RPC calls through the network transmission Serialization and Deserialization, different RPC framework has a different implementation mechanism. Mainly divided into text and binary two categories. The serialization mechanism of text category mainly includes XML and JSON format. The serialization mechanism of binary category commonly includes Java native serialization mechanism, hessian. protobuf, Thrift. Avro, Kryo, MessagePack, etc. Different serialization methods have great differences in readability, code stream size, supported data types and performance, requiring users to screen and filter according to their own actual situation.
- Stub Proxy: Can be regarded as a Proxy object, shielding the complicated network processing logic in RPC calls, making THE PRC calls transparent and maintaining the same code style as local calls.
- Transport: As the communication Transport module of RPC framework, it transmits request and reply messages between client and server through Socket.
- ServerCode: Specific implementation of the server service business logic. The following sections introduce the commonly used RPC frameworks.
RMI is introduced
Java RMI (Remote Method Invocation) is a Java based Remote Method Invocation technology, which is a Special RPC implementation of Java. It enables transparent communication and method calls between Java objects deployed on different hosts, as shown in the figure below.
RMI features are summarized below.
Support for true object-oriented polymorphism. Full support for object orientation is also one of RMI’s advantages over other RPC frameworks.
- Unique to the Java language, it does not support other languages and perfectly supports features unique to the Java language.
- Using Java’s native serialization mechanism, all serialized objects must implement the Java.io.Serializable interface.
- The underlying communication is based on the Socket implemented by BIO (Synchronous blocking I/O).
The performance of RMI is poor due to the inherent performance problems of the Java native serialization mechanism and BIO communication mechanism. This solution is not recommended for scenarios that have high performance requirements.
Sample native RMI code
Examples of RMI usage are described below
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;
}
Copy the code
RMI interface method definitions must explicitly declare that RemoteException is thrown
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;
}
Copy the code
Server-side method implementations must inherit from 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 () ; // Register service LocateRegistry. CreateRegistry (8801); Naming . bind ("rmi://localhost: 8801 /helloService", helloService) ; System. out.println ("ServerMain provide RPC service now") ; }}Copy the code
Client remotely invokes 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 the remote method system.out.println ("RMI server returns: "+ helloService.sayHello ("liyebing")); }}Copy the code
First run the server program ServerMain and then run ClientMain as follows:
The RMI server returns: Hello, liyebingCopy the code
RMI penetrates the firewall
RMI communication ports are randomly generated and may be blocked by firewalls. To prevent being blocked by the firewall, you need to specify the RMI communication port forcibly. RMISocketFactory class RMISocketFactory class
import java. io. IOException; import java.net. ServerSocket; import java.net. Socket; import java. rmi . server . RMISocketFactory; Public class Cus tomerSocketFactory extends RMISocketFactory { @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) ; }}Copy the code
Then inject the newly defined class into the Rmiserver side with the following code:
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) ; Rmisocketfactory.setsocketfactory (new Custome rSocketFactory())); HelloService helloService = new HelloServiceImpl () ; Naming.bind ("rmi://localhost: 8801/helloService" , helloService) ; System. out.println ("ServiceMain provide RPC service now.") ; }}Copy the code
CXF/Axis2 is introduced
WebService is a cross-platform RPC protocol. WebService technology stack consists of SOAP(SampleObject Access Protocol), UDDI (Universal Description, Discovery and Integration), Unified Description, Discovery and Integration), WSDL (Web Services Description Language). SOAP is a communication protocol that uses XML to encode data. It is independent of platform and language, simple and extensible. SOAP is based on HTTP protocol for data transmission, so 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 that is a universal description, discovery, and integration service. WSDL is a WebService description language written in XML that describes a WebService and how to access it.
Here are two WebServic implementations commonly used in Java development :CXF and Axis2. .
CXF is introduced
Apache CXF is an open source WebService RPC framework, which is the result of the merger of ObjectWebCeltix and CodehausXFire, two well-known open source projects. Apache XF contains a wide range of fully functional collections. The main features are as follows.
- Supports Web Services standards, including SOAP (SOAP1.1 and SOAP1.2) specifications, WSI BasicProfile, WSDL, ws-addressing, ws-policy, ws-reliablemessage ageing, 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).
- Supports multiple transport protocols, protocol binding, and data binding.
- Protocol binding: SOAP, REST/HTTP, AND XML.
- Data binding: JAXB 2.X, Aegis, Apache XMLBeans, etc.
The following illustrates the use of CXF through an integrated Spring Maven-based JavaWeb project. In order to demonstrate the convenience of the WebService server and client side to write a project inside. The structure of the project is shown below.
The key code for the CXF integration SpringMaven project sample is described below.
Define the server service interface HelloService, where the interface is indicated by the @webService annotation as a WebService remote service interface:
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; }}Copy the code
The implementation class of the WebService service interface in the above code is HelloServicelmpl, and the annotation @webService is used, and the corresponding interface is specified by endpointInterface to implement CXf.service.helloService.
The cxF-server. XML configuration is 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"/>
Copy the code
The web.xml configuration is as follows:
<? The 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>Copy the code
Maven dependency configuration for POM.xml is as follows:
The < 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>Copy the code
Deploy and run in the Tomcat Web container, and the result is shown in the following figure.
Deploy and run in Tomcat
Then run in the browser localhost: 8080 / ws/HelloWorld? WSDL, the result shown in the following figure shows that the WebService server service is published.
The CXF WebService publishes a WSDL file
The following describes how the client invokes the WebService 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>
Copy the code
In the command, serviceClass configures the WebService interface published by the server. Address indicates the HTTP address for the server to access the WebService (The WebService uses HTTP to communicate).
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")) ; }}Copy the code
The result is as follows
hello, liyebing
Copy the code
Axis2 introduces
Apache Axis2, a successor to Axis, is a new generation of SOAP engine and another very popular Web Services/SOAP/WSDL implementation besides CXF, with both Java and C implementations. Here is an introduction to the implementation of Java language.
Axis2 has the following main features.
- High performance: Axis2 has its own lightweight object model, AXIOM, and uses StAX (Streaming APIfor XML) technology for better performance and lower memory consumption than Axis1.x.
- Hot deployment :Axis2 is equipped with the ability to deploy Web services and handlers when the system is up and running. In other words, new services can be added to the system without having to shut down the server. Simply store the required Web service archive in the services directory of the repository, and the deployment model automatically deploys the service and makes it available. Use. .
- Asynchronous service support: Axis2 supports asynchrony with non-blocking clients and transhipment, 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 following illustrates Axis2 usage with a JavaWeb project that integrates Spring with Maven-based Java. In order to demonstrate the convenience of the WebService server and client code to write a project inside. The structure of the project is shown below
The key server-side code for Axis2WebService is described below.
Define the WebService service interface:
package axis2. service;
public interface HelloService {
public String sayHello(String content) ;
}
Copy the code
HelloService interface implementation:
package axis2. service;
public class HelloServiceImpl implements HelloService {
public String sayHello (String content) {
return "hello," + content;
}
Copy the code
The axis2-server. XML configuration file is used to declare instances of Spring service beans:
<bean id="hel loService" class="axis2. service . HelloServiceImpl"/>
Copy the code
The services.xml configuration file is used to describe the Axis2 service:
<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>
Copy the code
The content of web. XML 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>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>Copy the code
The 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>Copy the code
Deployed in Tomcat run, and then run in the browser HTP: / / ocalhos: 8080 / services/HelloService? WSDL, as shown in the figure below, indicates that the WebService server has been published.
The Axis2 client can invoke it in a number of ways, but here’s a dynamic invocation 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 the call parameter object[] paramArgs = new object[] {"liyebing"}; 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() ; }}}Copy the code
The running results are as follows:
hello, liyebing
Copy the code
conclusion
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 version of the RPC framework implemented by myself.