Java RMI (Remote Method Invocation) is a mechanism that allows users to access or invocate an object and a method running on another JVM (Java Virtual Machine). RMI is an implementation of RPC (Remote Procedure Call) in java with support of OOP (Object Oriented Paradigms). Instead of bothering IDL (Interface Define Language), users can build distributed applications by depending on interfaces in an easy and natural way.
Here is how a typical RMI invocation usually works:
(source:https://www.cs.rutgers.edu/~pxk/417/notes/images/rpc-rmi_flow.png)
Java RMI is a technique foundation stone of creating distributed applications in Java. The following EJB techniques and current framework of distributed services still inherit the fundamental concepts of Java RMI. In RMI invocation, there are some core concepts:
For 1. users are dependent on interfaces which should be implemented by server.
For 2. In J2SE 1.5 version and before, it needs to pre-compile Stub on client and Skeleton on server by rmic. In the later versions there is no need to do so.
The following is a code example of registry and look-up in RMI.
Hello obj = new HelloImpl(); // #1
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0); // #2
Registry registry = LocateRegistry.createRegistry(1099); // #3
registry.rebind("Hello", stub); // #4
Notes:
Initiate service object instance.
Create stub object to communicate with the server by UnicastRemoteObject.exportObject.
Create a local RMI registry service on port 1099 which is run on server. It can also be registered as an independent process.
Bind stub object into registry so the client can find the remote object by looking up Hello.
Registry registry = LocateRegistry.getRegistry(); // #1
Hello stub = (Hello) registry.lookup("Hello"); // #2
String response = stub.sayHello(); // #3
Notes:
The basic concepts of current framework of distributed service is similar to the one of RMI. They both use Java interface as service contract, register and look up by registry center and use agency to block the details of remote communications. Specifically, Dubbo has following four types of roles to play when running:
Deploy stage
Run stage
The applications of Dubbo are usually assembled by Spring. To obtain an available Dubbo application quickly, the example shown here abandons complex configurations but to create service provider and consumer in Dubbo API oriented way. Additionally, the registry center and monitor center do not need installation or configuration in this example.
In production environment, the service of Dubbo usually requires cooperation with a distributed service registry center, such as ZooKeeper. For convenience, Dubbo offers two ways to avoid extra work of building registry center, namely direct connection [2] and assembled podcast [3] respectively. In this example, the latter way is applied to register and look up service.
public interface GreetingsService {
String sayHi(String name); // #1
}
Notes:
public class GreetingsServiceImpl implements GreetingsService { // #1
@Override
public String sayHi(String name) {
return "hi, " + name; // #2
}
}
Notes:
public class Application {
public static void main(String[] args) throws IOException {
ServiceConfig<GreetingsService> service = new ServiceConfig<>(); // #1
service.setApplication(new ApplicationConfig("first-dubbo-provider")); // #2
service.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); // #3
service.setInterface(GreetingsService.class); // #4
service.setRef(new GreetingsServiceImpl()); // #5
service.export(); // #6
System.in.read(); // #7
}
}
Notes:
multicast://224.5.6.7:1234
. The valid range of assembled address is 224.0.0.0 - 239.255.255.255public class Application {
public static void main(String[] args) {
ReferenceConfig<GreetingsService> reference = new ReferenceConfig<>(); // #1
reference.setApplication(new ApplicationConfig("first-dubbo-client")); // #2
reference.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); // #3
reference.setInterface(GreetingsService.class); // #4
GreetingsService greetingsService = reference.get(); // #5
String message = greetingsService.sayHi("dubbo"); // #6
System.out.println(message); // #7
}
}
Notes:
dubbo
as input parameter.hi, dubbo
.The complete example can be found at https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-api. In the complete version, it is convenient to execute by maven in command line with the configuration of exec-maven-plugin. Of course, it can also be executed directly in IDE. However, there is one noteworthy thing that because of using assembled way to look up service, it needs to assign -Djava.net.preferIPv4Stack=true when running.
Synchronize the example codes and build by the following command lines:
$ git clone https://github.com/apache/dubbo-samples.git
$ cd dubbo-samples/java/dubbo-samples-api/
$ mvn clean package
INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building dubbo-samples-api 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ dubbo-samples-api ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.182 s
[INFO] Finished at: 2018-05-28T14:56:08+08:00
[INFO] Final Memory: 20M/353M
[INFO] ------------------------------------------------------------------------
The build is finished when it shows BUILD SUCCESS
. Then comes the running stage.
Run the service provider by the following maven command lines:
$ mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.provider.Application exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building dubbo-samples-api 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ dubbo-samples-api ---
log4j:WARN No appenders could be found for logger (org.apache.dubbo.common.logger.LoggerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
first-dubbo-provider is running.
When first-dubbo-provider is running appears, the service provider is ready to be called by the client.
Run the service consumer by the following maven command lines:
$ mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.consumer.Application exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building dubbo-samples-api 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ dubbo-samples-api ---
log4j:WARN No appenders could be found for logger (org.apache.dubbo.common.logger.LoggerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
hi, dubbo
hi, dubbo
is the execution results from service provider.
Dubbo also provides a public platform that can create a Dubbo application quickly based on Spring Boot. Visit http://start.dubbo.io and follow the figure below to create an example project:
Notes:
com.example
.demo
.com.example.HelloService
.1.0.0
.server
.This example shows how to generate a server. Similarly, it can generate a client by selecting client on the generation interface.
Open the generated project with an IDE and to see the application is a typical Spring Boot application with the following program entry:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
new EmbeddedZooKeeper(2181, false).start(); // #1
SpringApplication.run(DemoApplication.class, args); // #2
}
}
Notes:
Run it directly in IDE and here are the results:
2018-05-28 16:59:38.072 INFO 59943 --- [ main] a.b.d.c.e.WelcomeLogoApplicationListener :
████████▄ ███ █▄ ▀█████████▄ ▀█████████▄ ▄██████▄
███ ▀███ ███ ███ ███ ███ ███ ███ ███ ███
███ ███ ███ ███ ███ ███ ███ ███ ███ ███
███ ███ ███ ███ ▄███▄▄▄██▀ ▄███▄▄▄██▀ ███ ███
███ ███ ███ ███ ▀▀███▀▀▀██▄ ▀▀███▀▀▀██▄ ███ ███
███ ███ ███ ███ ███ ██▄ ███ ██▄ ███ ███
███ ▄███ ███ ███ ███ ███ ███ ███ ███ ███
████████▀ ████████▀ ▄█████████▀ ▄█████████▀ ▀██████▀
:: Dubbo Spring Boot (v0.1.0) : https://github.com/dubbo/dubbo-spring-boot-project
:: Dubbo (v2.0.1) : https://github.com/alibaba/dubbo
:: Google group : http://groups.google.com/group/dubbo
2018-05-28 16:59:38.079 INFO 59943 --- [ main] e.OverrideDubboConfigApplicationListener : Dubbo Config was overridden by externalized configuration {dubbo.application.name=dubbo-demo-server, dubbo.application.qosAcceptForeignIp=false, dubbo.application.qosEnable=true, dubbo.application.qosPort=22222, dubbo.registry.address=zookeeper://localhost:2181?client=curator, dubbo.registry.id=my-registry, dubbo.scan.basePackages=com.example} #1
...
2018-05-28 16:59:39.624 INFO 59943 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 1.746 seconds (JVM running for 2.963)
Notes:
dubbo.
Is defined in main/resources/application.properties.If qos is activated during generation, the service can be watched and managed by telnet or nc.
$ telnet localhost 22222
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
████████▄ ███ █▄ ▀█████████▄ ▀█████████▄ ▄██████▄
███ ▀███ ███ ███ ███ ███ ███ ███ ███ ███
███ ███ ███ ███ ███ ███ ███ ███ ███ ███
███ ███ ███ ███ ▄███▄▄▄██▀ ▄███▄▄▄██▀ ███ ███
███ ███ ███ ███ ▀▀███▀▀▀██▄ ▀▀███▀▀▀██▄ ███ ███
███ ███ ███ ███ ███ ██▄ ███ ██▄ ███ ███
███ ▄███ ███ ███ ███ ███ ███ ███ ███ ███
████████▀ ████████▀ ▄█████████▀ ▄█████████▀ ▀██████▀
dubbo>
dubbo>ls
As Provider side:
+------------------------------+---+
| Provider Service Name |PUB|
+------------------------------+---+
|com.example.HelloService:1.0.0| Y |
+------------------------------+---+
As Consumer side:
+---------------------+---+
|Consumer Service Name|NUM|
+---------------------+---+
Currently, qos supports following command lines. For more information please refer to the official document. [^4]:
In this tutorial, we start with RMI and introduce the basic concepts in Java distributed invocations. Based on interface programming, it disguises remote calls as local by agency and run the service registry and looking up by registry center.
Then for simplicity, we introduce how to develop a complete Dubbo demo in an easy way of assembled registry and direct Dubbo API oriented programming. Additionally, we look into the usage of ServiceConfig and RefenceConfig, which is of great help for further using Spring XML configuration and the programming pattern of Spring Boot.
Eventually, we give an outline of how to create a Dubbo application quickly based on Spring Boot using the public resources, start.dubbo.io, provided by the Dubbo development team and operate and maintain the Dubbo service by qos.