= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

Source yinwj.blog.csdn.net/article/det…

1, an overview of the

After summarizing the basic knowledge of data description format and IO communication model. We can finally get to the focus of this series of posts: inter-system communication management. In this chapter I will introduce RMI in detail, introduce an important inter-system communication management specification RPC, and continue to discuss some RPC implementations; By analyzing the technical characteristics of PRC, this paper introduces ESB, another management standard of inter-system communication, and introduces some concrete implementation of ESB. Finally, we introduce SOA: Service-oriented software Architecture.

2. Basic use of RMI

RMI (Remote Method Invocation) is an implementation of the technical framework for object Method Invocation between JVMS that JAVA provided in JDK 1.1 (improved in later versions of the JDK). With RMI technology, one local JVM can call an object method that exists in another JVM as if it were just calling an object method in the local JVM. For example, the following call in the RMI client:

List< UserInfo > users = remoteServiceInterface.queryAllUserinfo();

The remoteServiceInterface object looks like a normal object, but the actual method implementation of the remoteServiceInterface object is not in the local JVM. It is in a remote JVM (the REMOTE JVM can be the RMI client on the same physical machine or on a different physical machine)

In writing this blog, I looked up some Internet sources. It is found that there are few articles that explain RMI thoroughly. There are a number of articles stating that RMI technology is outdated and that it is not performing well. Some even compare the performance of JAVA native Socket framework with RMI technical framework. The article describing the underlying IO model of RMI was nowhere to be found, except for a few words stating that RMI has nothing to do with NIO.

1-1. RMI Application Scenarios

RMI is based on The JAVA language, that is, in the description of RMI technical framework, only the Server side uses the JAVA language and the Client side also uses the JAVA language. To use RMI technology (there is currently an open source project at codeproject.com called “RMI for C++” that implements JAVA To C++ RMI calls. However, this is a third-party implementation and is not a standard RMI framework definition for Java, so it is outside the scope of our discussion).

RMI is suitable for situations where both systems are constructed primarily using the JAVA language and cross-language support is not considered. And the communication speed of two JAVA systems is required.

RMI is a good, special RPC implementation: it uses the JRMP protocol to host data descriptions, and it can use both BIO and NIO IO communication models. The RMI framework can be used in large-scale clustered systems, depending on the technical background of your product, the technical background of your team, the business background of your company, and even the non-technical background of your customers. (But if you say that your own distributed system performance is better than RMI, then I am superficial: in our country like Bill Joy, Ann Wollrath are a handful!!)

1-2. Basic composition of RMI framework

Although RMI has been available since JDK.1.1. However, RMI has been improved in JDK1.5. So our subsequent code examples and tutorials are based on the latest RMI framework features.

To define and use a system that works based on the RMI framework, you need to do at least a few things:

1. Define RMI Remote interface 2. Implement RMI Remote interface 3. The details of this step vary from JDK version to JDK version (for example, Skeleton doesn’t need manual after JDK1.5); The way the RMI registry works also affects the question of whether a Stub needs command line generation. 4. Register the RMI Remote interface we implemented in step 2 with the RMI registry. 5. Create a Remote client and use Java naming service to find the registered RMI service at the IP address :PORT where the RMI registry is located. 6. Remote clients call RMI interfaces that exist on Remote JVMS in the same way they call objects that exist on local JVMS.

The following diagram illustrates the relationship between these concept names, showing one of the ways the RMI framework in JDK.5 works (note, one of the ways it works). That said, RMI frameworks don’t always work this way, and we’ll describe another way RMI works later) :

1-3. Code Example 1

In this code, we’ll use “Local RMI registry” to make the specific PROVIDER of RMI services and the RMI registry work on the same JVM, and walk you through the basic process of defining, writing, registering, and invoking RMI services:

First we must define the RMI service interface as follows:

package testRMI; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.List; import testRMI.entity.UserInfo; Public interface RemoteServiceInterface extends Remote {/** * public List<UserInfo> queryAllUserinfo() throws RemoteException; } 123456789101112131415Copy the code

Very simple code, there should be no more explanation. This defined interface method, if placed in some business system A, can be understood as querying all available user profiles in that system A. Note that this interface inherits the Java.rmi. Remote interface, which is a feature of the “RMI Service Interface” definition.

If there is an interface definition, it is natural to implement this interface:

package testRMI; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.List; import testRMI.entity.UserInfo; /** * RMI service interface RemoteServiceInterface <br> * Note that the UnicastRemoteObject parent is inherited. * inherits from this parent class, * @author yinwenjie * */ Public class RemoteUnicastServiceImpl extends UnicastRemoteObject implements RemoteServiceInterface {/** * Note that RemoteObject does not have a default constructor * @throws RemoteException */ protected RemoteUnicastServiceImpl() throws RemoteException { super(); } private static final long serialVersionUID = 6797720945876437472L; /* (non-Javadoc) * @see testRMI.RemoteServiceInterface#queryAllUserinfo() */ @Override public List<UserInfo> queryAllUserinfo() throws RemoteException { List<UserInfo> users = new ArrayList<UserInfo>(); UserInfo user1 = new UserInfo(); user1.setUserAge(21); user1.setUserDesc("userDesc1"); user1.setUserName("userName1"); user1.setUserSex(true); users.add(user1); UserInfo user2 = new UserInfo(); user2.setUserAge(21); user2.setUserDesc("userDesc2"); user2.setUserName("userName2"); user2.setUserSex(false); users.add(user2); return users; }} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051Copy the code

There is also the Userinfo we define, which is a normal POJO object:

package testRMI.entity; import java.io.Serializable; import java.rmi.RemoteException; public class UserInfo implements Serializable { /** * */ private static final long serialVersionUID = -377525163661420263L; private String userName; private String userDesc; private Integer userAge; private Boolean userSex; public UserInfo() throws RemoteException { } /** * @return the userName */ public String getUserName() { return userName; } /** * @param userName the userName to set */ public void setUserName(String userName) { this.userName = userName; } /** * @return the userDesc */ public String getUserDesc() { return userDesc; } /** * @param userDesc the userDesc to set */ public void setUserDesc(String userDesc) { this.userDesc = userDesc; } /** * @return the userAge */ public Integer getUserAge() { return userAge; } /** * @param userAge the userAge to set */ public void setUserAge(Integer userAge) { this.userAge = userAge; } /** * @return the userSex */ public Boolean getUserSex() { return userSex; } /** * @param userSex the userSex to set */ public void setUserSex(Boolean userSex) { this.userSex = userSex; } } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 656667686970717273747576Copy the code

With the interface definition and implementation of RMI Server in place, the final step in writing the code is to register the RMI Server to run in the “RMI registry.” This allows RMI clients to call the RMI Server. The following code registers the RMI Server in the “local RMI registry” :

package testRMI; import java.rmi.Naming; import java.rmi.registry.LocateRegistry; Public class RemoteUnicastMain {public static void main(String[] args) throws Exception {/* * Locate Registry, You can think of it as the RMI service registry, or the RMI service location repository. * The primary role is to maintain a "location where RMI specific services can be properly provided." * Each RMI service provider registers its Stub with the Locate Registry to indicate that it "can provide services." * * There are two ways to manage the Locate Registry: one is to start the registry from the command line of the operating system; * Another option is to use the LocateRegistry class in your code. * * LocateRegistry class have a createRegistry method, can be in the physical machine to create a "local RMI registry" * * / LocateRegistry createRegistry (1099); // Here is the RMI Server implementation registered (bound/rebound) with LocateRegistry. RemoteUnicastServiceImpl remoteService = new RemoteUnicastServiceImpl(); // With Java name service technology, specific RMI Server implementations can be bound to an access path. Registered to the LocateRegistry Naming. The rebind (" rmi: / / 127.0.0.1:1099 / queryAllUserinfo ", remoteService); /* * In case you already have an accessible remote RMI registry. If the RMI registry is running on another JVM, the JVM classpath of the remote RMI registry must have a Stub for this Server. May be the same physical machine may not be the same physical machine) * Naming the rebind (" rmi: / / 192.168.61.1:1099 / queryAllUserinfo ", remoteService); * * /}} 12345678910111213141516171819202122232425262728293031323334Copy the code

This will allow the Client we write to call the RMI Server. But before giving the client-side code, there are a few more details about the code for the first few classes:

  • Since we created a “local RMI registry” using LocateRegistry, there is no need to use the Rmic command to generate stubs. This is because the JVM for the RMI Sever real service is the same JVM for the RMI registry.

  • Can the JVM for the RMI Sever real service and the JVM for the RMI registry be two different JVMS? B: Sure. And this is the real cash out of the flexibility and robustness of the RMI framework.

  • Note the definition of RemoteUnicastServiceImpl, which inherits UnicastRemoteObject. In general, RMI Server implementations can inherit from two parent classes: UnicastRemoteObject and Activatable (which will be covered in the next article).

  • The former means that the real service provider of RMI Server will work on a “native JVM”; The latter means that the real service provider of RMI Server is not running on the “local JVM”, but can be serialized to the “Remote JVM” (that is, the JVM on which the Remote RMI registry is located) through the “RMI Remote Server activation” technology, and then loaded and run in time by the “Remote JVM”.

  • Notice again the difference between “Naming. Rebind” and “Naming. Bind”. If the service name already exists in “RMI registry” during “rebinding”, the Remote Object previously bound will be replaced. The system will throw an error if the RMI registry already has the service name when “bind” is executed. So unless you have specific business requirements, it is recommended to use the Rebind method for Remote Object binding.

  • Also note the difference between registry. Rebind and Naming. Rebind bindings. The former uses the RMI registry binding, so there is no need to write the full RMI URL. The latter is bound through Java’s name service, which is the RMI URL to be written in the binding because the name service does more than provide a query service for the RMI framework.

The following code is the RMI Client code:

package testRMI; import java.rmi.Naming; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.log4j.BasicConfigurator; import testRMI.entity.UserInfo; / * * * client calls the RMI test * @ author yinwenjie * * / public class RemoteClient {static {BasicConfigurator. Configure (); } private static final Log LOGGER = logFactory.getLog (remoteclient.class); Public static void main(String[] args) throws Exception {// The Java name Service technology is used to search RMI interfaces. RemoteServiceInterface remoteServiceInterface = (RemoteServiceInterface) Naming. Lookup (" rmi: / / 192.168.61.1 queryAllUserinfo "); List<UserInfo> users = remoteServiceInterface.queryAllUserinfo(); RemoteClient.LOGGER.info("users.size() = " +users.size()); }} 12345678910111213141516171819202122232425262728293031323334Copy the code

So how do I run this code? If you wrote your first RMI Server and RMI Client using Eclipse, and you use the “local RMI registry.” You don’t need to do any configuration, script specification, etc. (no need to set JRE permissions, no need to specify classpath, no need to generate stubs and skeletons) to see RMI run and call:

The following is the effect of RMI service registration and execution on RemoteUnicastMain:

As you can see, the entire application does not exit after executing the code in RemoteUnicastMain. The diagram below:

This is because the application assumes the service invocation of a “real RMI Server implementation.” If it exits, the RMI registry cannot request a real service implementation.

Here’s how RemoteClient calls RMI services:

Obviously the console will return

0 [main] INFO testRMI.RemoteClient – users.size() = 2

1-4. Code Example 2

Well, at this point in the article I have to admit that I was misleading. Because the above code does not address Stub issues, nor does it address the RMI registry. So in sample code 1, we saw that the RMI registry and RMI Server implementation can be run in two JVMS; We also mentioned that stubs need to be generated manually. So how do you do this?

  • First we need to rewrite the RemoteUnicastMain class to remove the LocateRegistry class from RemoteUnicastMain to create the “local RMI registry” :

    package testRMI;

    import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry;

    public class RemoteRegistryUnicastMain { public static void main(String[] args) throws Exception { /* * We through LocateRegistry the get method, for the existence of a remote JVMS RMI Registry * * / Registry Registry. = LocateRegistry getRegistry (” 192.168.61.1 “, 1099);

    // The following is the Stub for RMI Server to bind/rebind to the remote RMI registry. // under jVM-CLASspath of the same remote RMI registry, RemoteUnicastServiceImpl remoteService = new RemoteUnicastServiceImpl(); / * * in. Don't write LocateRegistry createRegistry (1099); In the case of. * The following code is to register the remote RMI registry (an RMI registry running on another JVM, * It may or may not be the same physical machine.) * * The registered RMI registry exists at 192.168.61.1. * * When using registry for binding or rebinding, No need to write the full RMI URL * */ Registry. Rebind ("queryAllUserinfo", remoteService); }Copy the code

    } 1234567891011121314151617181920212223242526272829

  • Then we manually generate stubs (called piles in RMI) for RMI Remote Server implementation RemoteUnicastServiceImpl; Why would you want to generate it? Because the RMI Remote Server implementation and the RMI registry will work on two separate JVMS, the RMI registry needs to know basic information about the Server implementation (including class method information, class references, and so on), which is defined in the Stub class. Here we generate stubs for Windows (the process is basically the same for Linux) :

rmic -classpath E:\testworkspace\testBSocket\target\classes testRMI.RemoteServiceImpl

The Dos window code above explains:

The rmic command is used to generate Stub and Skeleton (JDK1.5+ will no longer generate Skeleton)

-classpath: indicates the classpath parameter. Specifies the location of the class directory. This parameter has the same meaning as the CLASSPATH parameter you set in the environment variable when you installed the JDK. However, in my environment, the project compiled path is E:\ testWorkspace \testBSocket\target\classes. This path is not set in the environment variable, so it needs to be specified when generating stubs (otherwise rMIC cannot identify which root path to identify the class).

– testRMI. RemoteServiceImpl: to generate a Stub RMI Server service implementation class. This class must implement the java.rmi.Remote interface.

After the implementation is complete, you can see the generated Stub class in the corresponding class directory. Remoteunicastserviceimpl_stub. class is the Stub class just generated. This Stub class and RemoteServiceInterface need to be placed under the CLASspath where the RMI registry runs the JVM.

  • Next we start the remote “RMI Registry” service:

// Set classpath set classpath =% classpath %; E: \testworkspace\testBSocket\target\classes

/ / under Linux, so command to export the CLASSPATH = $CLASSPATH: / usr/Java/CLASSPATH

// Start rmiregistry -p 1099

If the “-p” port parameter is not specified, the default port is 1099.

  • Then use the modified RemoteUnicastMain to register the RMI Remote Server in the Remote “RMI registry” :

The RMI Remote Server is now registered with the Remote “RMI registry”. But before RemoteUnicastMain RemoteRegistryUnicastMain execution effect and the execution of the effect is the same. The application does not exit when the bind/rebind statement is executed. The reason is the same as in example code 1.

  • The IP address of the CALLING RMI URL needs to be changed:

    package testRMI;

    import java.rmi.Naming; import java.util.List;

    import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.log4j.BasicConfigurator;

    import testRMI.entity.UserInfo;

    / * *

    • The client invokes the RMI test
    • @author yinwenjie

    */ public class RemoteClient { static { BasicConfigurator.configure(); }

    Private static final Log LOGGER = logFactory.getLog (remoteclient.class); public static void main(String[] args) throws Exception { RemoteServiceInterface remoteServiceInterface = (RemoteServiceInterface) Naming. Lookup (" rmi: / / 192.168.61.1:1099 / queryAllUserinfo "); List<UserInfo> users = remoteServiceInterface.queryAllUserinfo(); RemoteClient.LOGGER.info("users.size() = " +users.size()); }Copy the code

    } 123456789101112131415161718192021222324252627282930313233

3. JAVA RMI principle

Starting with the next article, we’ll continue to explain how JAVA RMI works. The IO communication model of RMI framework is analyzed in detail.