How EJB works
Study Notes on working principles of EJB
1. How RMI works
2 WebSphere implementation
3 WebLogic implementation
4. Understanding
1: How RMI works
The essence of RMI is to implement the call between different JVMs. The implementation method is to open one stub and skeleton in each of the two JVMs. The two use socket communication to transmit parameters and return values.
There are quite a few examples of RMI code available on the Internet, but most of them are implemented through extend the interface java. RMI. Remote, which has been well encapsulated and can hardly help but make people feel confused. The example below is what I saw in Enterprise JavaBeans. Although it is rough, it is intuitive and helps me quickly understand how it works.
1. Define a person interface. There are two business methods, getage () and getname ()
Code:
Public interface person {
Public int getage () throws throwable;
Public String getname () throws throwable;
}
2. personserver class for implementing person
Code:
Public class personserver implements person {
Int age;
String name;
Public personserver (string name, int age ){
This. Age = age;
This. Name = Name;
}
Public int getage (){
Return age;
}
Public String getname (){
Return name;
}
}
3. Now, we need to call the getage () and getname () businesses on the client machine.
Method, you have to write the corresponding stub (client) and skeleton (server) programs. This is the implementation of stub:
Code:
Import java. Io. objectoutputstream;
Import java. Io. objectinputstream;
Import java.net. Socket;
Public class person_stub implements person {
Socket socket;
Public person_stub () throws throwable {
// Connect to skeleton
Socket = new socket ("computer_name", 9000 );
}
Public int getage () throws throwable {
// Pass method name to skeleton
Objectoutputstream outstream =
New objectoutputstream (socket. getoutputstream ());
Outstream. writeobject ("Age ");
Outstream. Flush ();
Objectinputstream instream =
New objectinputstream (socket. getinputstream ());
Return instream. readint ();
}
Public String getname () throws throwable {
// Pass method name to skeleton
Objectoutputstream outstream =
New objectoutputstream (socket. getoutputstream ());
Outstream. writeobject ("name ");
Outstream. Flush ();
Objectinputstream instream =
New objectinputstream (socket. getinputstream ());
Return (string) instream. readobject ();
}
}
Note that, like person_stub and personserver, both implements
Person. Both implement the getage () and getname () Business
The difference is that the personserver is actually implemented, and the person_stub is used to establish a socket connection, send a request to skeleton, and then
Skeleton calls the personserver method and finally receives the returned results.
4. Skeleton implementation
Code:
Import java. Io. objectoutputstream;
Import java. Io. objectinputstream;
Import java.net. Socket;
Import java.net. serversocket;
Public class person_skeleton extends thread {
Personserver myserver;
Public person_skeleton (personserver server ){
// Get reference of Object Server
This. myserver = server;
}
Public void run (){
Try {
// The new socket at port 9000
Serversocket = new serversocket (9000 );
// Accept stub's request
Socket socket = serversocket. Accept ();
While (socket! = NULL ){
// Get stub's request
Objectinputstream instream =
New objectinputstream (socket. getinputstream ());
String method = (string) instream. readobject ();
// Check Method Name
If (method. Equals ("Age ")){
// Execute Object Server's Business Method
Int age = myserver. getage ();
Objectoutputstream outstream =
New objectoutputstream (socket. getoutputstream ());
// Return result to stub
Outstream. writeint (AGE );
Outstream. Flush ();
}
If (method. Equals ("name ")){
// Execute Object Server's Business Method
String name = myserver. getname ();
Objectoutputstream outstream =
New objectoutputstream (socket. getoutputstream ());
// Return result to stub
Outstream. writeobject (name );
Outstream. Flush ();
}
}
} Catch (throwable t ){
T. printstacktrace ();
System. Exit (0 );
}
}
Public static void main (string ARGs []) {
// New Object Server
Personserver person = new personserver ("Richard", 34 );
Person_skeleton skel = new person_skeleton (person );
Skel. Start ();
}
}
The skeleton class extends from thread, which runs in the background and receives requests sent by the client at any time. And according to
Key to call the corresponding business method.
5. The last one is the implementation of the client.
Code:
Public class personclient {
Public static void main (string [] ARGs ){
Try {
Person = new person_stub ();
Int age = person. getage ();
String name = person. getname ();
System. Out. println (name + "is" + age + "years old ");
} Catch (throwable t ){
T. printstacktrace ();
}
}
}
The essence of the client is that it needs to know the definition of the person interface, and instance a person_stub, call the business method through stub,
As for how stub communicates with the server, the client does not have to worry about it.
Note:
Person = new person_stub ();
Instead
Person_stub person = new person_stub ();
Why? Because interface-oriented programming is required.
//In essence, RMI generates two stub and skeleton classes to PASS Parameters and return values.
//Similar to the previously written chat room program, the passed object should implement the java. Io. serializable interface.
2: WebSphere implementation
EJB class overview
Let's talk about the call relationships of various classes in combination with WebSphere.
Suppose we want to create a sessionbean to read user information. We need to write three files:
1. userservicehome. Java
Home Interface
2. userservice. Java
Remote Interface
3. userservicebean. Java
Bean implementation
Wsad will eventually generate 10 classes. What are the other seven? Let's count them one by one:
4. _ userservicehome_stub.java
This is of course the stub class of the home interface on the client side (dynamic loading). It implements userservicehome.
5. _ ejsremotestatelessuserservicehome_a940aa04_tie.java
The home interface is in the skeleton class on the server. "a940aa04" should be randomly generated. This flag is available in all other related class names.
String. Tie is the name of skeleton by CORBA.
6. ejsremotestatelessuserservicehome_a940aa04.java
The home interface is implemented on the server. Of course, it is also implements userservicehome.
7. ejsstatelessuserservicehomebean_a940aa04.java
Called by #6, create _ userservice_stub. (Why #6 cannot create _ userservice_stub directly? I will talk about it later .)
8. _ userservice_stub.java
Stub class of the remote interface on the client (dynamic loading. It implements userservice.
9. _ ejsremotestatelessuserservice_a940aa04_tie.java
The skeleton class of the remote interface on the server.
10. ejsremotestatelessuserservice_a940aa04.java
The remote interface is implemented on the server. Of course, it is also implements userservice. In addition, it calls userservicebean --
That is, the bean implementation class we wrote-the business method in it.
So what is the call relationship between classes? In short, there are two RMI loops.
First RMI Loop
Let's take a look at how the client program is written:
Code:
Try {
Initialcontext CTX = new initialcontext ();
// Step 1
Userservicehome =
(Userservicehome) portableremoteobject. Narrow (
CTX. Lookup (jndistring ),
Userservicehome. Class );
// Home: _ userservicehome_stub
System. Out. println (home. tostring ());
// Step 2
Userservice object = home. Create ();
// Ojbect: _ userservice_stub
System. Out. println (object. tostring ());
// Step 3
Int userid = 1;
Userinfo UI = object. getuserinfo (userid );
}
After step 1, we get a home object defined by userservicehome (interface). Then, which class is home?
What about instance? Run debug to check whether the home is an instance of _ userservicehome_stub.
Starting from step 2, we focus on it. Although there is only one simple line of code,
Userservice object = home. Create ();
But how does the system behind him work? Let's go to the Code:
1. Call home. Create ()
Code:
Userservicehome home;
Userservice OBJ = home. Create ();
2. Actually, _ userservicehome_stub.create () is called. In this method, Stub sends a create string to skeleton.
:
Code:
Org. Omg. CORBA. Portable. outputstream out = _ Request ("CREATE", true );
In = (Org. Omg. corba_2_3.portable.inputstream) _ invoke (out );
3. The server skeleton receives the request from stub and calls the corresponding method:
Code:
_ Ejsremotestatelessuserservicehome_a940aa04_tie. _ invoke (){
......
Switch (method. Length ()){
Case 6:
If (method. Equals ("CREATE ")){
Return create (in, reply );
}
......
}
}
Code:
_ Ejsremotestatelessuserservicehome_a940aa04_tie.create (){
Ejsremotestatelessuserservicehome_a940aa04 target = NULL;
Result = target. Create ();
Org. Omg. CORBA. Portable. outputstream out = reply. createreply ();
Util. writeremoteobject (Out, result );
Return out;
}
4. Skeleton calls the create method of the server implementation class of userservicehome.
Code:
Ejsremotestatelessuserservicehome_a940aa04.create (){
Userservice _ ejs_result;
_ Ejs_result = ejsstatelessuserservicehomebean_a940aa04.create ();
}
5. #4 call ejsstatelessuserservicehomebean_a940aa04.create ()
Code:
Userservice result = super. createwrapper (New beanid (this, null ));
So far, we finally end the first RMI loop and get the stub class _ userservice_stub of the remote interface userservice, Which is #5
Result.
Here is a question, why #4 does not directly create _ userservice_stub, but another #5 hand? Because #4 extends from
Ejswrapper, which does not have the ability to create stub, so you must use #5, which extends from ejshome to generate
Stub. If you do not want to generate this stub, you can skip step #5.
The second RMI Loop
OK, now we got the object which is instanceof _ userservice_stub, and implements userservice
Now our client is in the third step:
Userinfo UI = object. getuserinfo (userid );
Continue to read the code and start the second RMI loop:
1. Call object. getuserinfo ()
Code:
Userservice object;
Object. getuserinfo (userid );
2. Call _ userservice_stub.getuserinfo (int
Arg0). In this method, Stub sends a getuserinfo string and arg0 parameter to skeleton:
Code:
Org. Omg. CORBA. Portable. outputstream out = _ Request ("getuserinfo", true );
Out. write_long (arg0 );
In = (Org. Omg. corba_2_3.portable.inputstream) _ invoke (out );
3. The server skeleton receives the request from stub and calls the corresponding method:
Code:
_ Ejsremotestatelessuserservice_a940aa04_tie. _ invoke (){
Switch (method. charat (5 ))
{
Case 83:
If (method. Equals ("getuserinfo ")){
Return getuserinfo (in, reply );
}
......
}
}
_ Ejsremotestatelessuserservice_a940aa04_tie.getuserinfo (){
Ejsremotestatelessuserservice_a940aa04 target = NULL;
Int arg0 = in. read_long ();
Userdto result = target. getuserinfo (arg0 );
Org. Omg. corba_2_3.portable.outputstream out = reply. createreply ();
Out. write_value (result, userdto. Class );
Return out;
}
4. Skeleton calls the getuserinfo method of the server implementation class of userservice.
Code:
Ejsremotestatelessuserservice_a940aa04.getuserinfo (){
Userservicebean _ ejs_beanref = container. preinvoke (this, 0, _ ejs_s );
_ Ejs_result = _ ejs_beanref.getuserinfo (ID );
}
Finally, #4 finally called the getuserinfo method in userservicebean we wrote. This is what we really want to do.
.
So far, the second RMI loop has finally ended.
Call Flowchart
Looking back at the above analysis, we can clearly see the process of two RMI loops (see the link) and describe the entire process:
Http://www.pbase.com/image/27229257
The numbers 1, 6, and 10 in yellow are written by programmers, and the rest are generated by the system.
#1 is the home interface, #2 and #4 are implements it.
#6 is the remote interface. #7 and #9 are all implements.
#10 is bean implementation.
3: Weblogic implementation
A remote object must contain at least four class files: remote objects, interfaces of remote objects, Stub of objects implementing remote interfaces, and ske of objects.
Leton class files.
In EJB, there must be at least 10 classes:
Bean class, bean implementation class for specific app Server
Bean remote interface, remote interface implementation class for specific app server, specific app
Stub class and skeleton class of the remote interface implementation class of server
Bean home interface, home interface implementation class of the specific app server, specific app
Stub class and skeleton class of the home interface implementation class of server
Different from RMI, only three of the 10 classes in EJB really need to be written by the user, namely the Bean class and its remote interface and the home interface.
As for how the other seven classes are generated, where they are packaged, or whether more class files are required, the app
Server shows a big difference and cannot be generalized.
For WebLogic, the bean implementation class of Weblogic and the Weblogic implementation class of the two interfaces are packaged into ejbc.
In the jar package, the three class files can be seen. The stub class and skeleton class of Weblogic implementation class of the home interface and remote interface
Class: When the EJB is deployed to WebLogic, WebLogic dynamically generates the bytecode of the stub and skeleton classes.
File.
For a client to remotely call ejbs, it must go through multiple RMI loops of two remote objects. First, find the home interface through JNDI to obtain the home
Interface implementation class, this process is actually quite complicated. First, find the Weblogic implementation class of the home interface, and then create a home Interface Web
The stub class object instance of the logic implementation class will be serialized and transmitted to the client (note that stub class instances are in 1st RMI loops
So the client does not need to save the studio class of the Weblogic implementation class of the home interface.) Finally, the client obtains the Stu
Class B object instance (normal RMI needs to save stub class on the client, but EJB does not, because the server will send stub class object instances
Client ).
After the client obtains the stub class object instance of the Weblogic implementation class of the home interface provided by the server, it calls the create method of the stub class.
The code is home. Create (), but there are many things to do in the background), so after 2nd RMI loops, on the server side, WebLogic of the home interface
The skeleton class of the implementation class receives the call information of the stub class and then calls the create method of the Weblogic implementation class of the home interface.
On the server side, the create method of the Weblogic implementation class of the home interface then calls the ejbcreate method of the Weblogic implementation class of the bean class.
Create or assign an EJB instance to the service end, and then serialize the stub class object instance of the Weblogic implementation class of the remote interface of the EJB instance
To the client.
The client receives the stub class object instance of the Weblogic implementation class of the remote interface and calls the method of this object instance (in the client code
Is actually a call to the remote interface), will be sent to the server remote interface WebLogic implementation class skeleton class object, and skele
The ton Class Object then calls the Weblogic implementation class of the corresponding remote interface, and then the Weblogic implementation class of the remote interface calls
Blogic implementation class to complete a remote call to the EJB object.
After reading the post, I still didn't think it was clear. Since I wrote the post, I wanted to make it clear.
Take RMI for example, there are four classes: remote objects, object interfaces, Stub classes of objects, and skeleton classes. The object itself and
The stub class of the image also implements the interface class. When the client code calls a remote object, although the interface is manipulated in the code
Is manipulating the stub class, for example:
Interface Class: Hello
Remote Object: hello_server
Stub class: hello_stub
Skeleton class: hello_skeleton
Write the client code as follows:
Hello H = new hello_stub ();
H. getstring ();
We won't write it like this:
Hello_stub H = new hello_stub ();
H. getstring ();
Even if the interface implementation class is replaced, you do not need to change the code. Therefore, the client needs hello. Class and hello _
Stub. class files. But for EJB, hello_stub.class is not required, because the server will send it, But hello.
The class file client cannot be saved and must be available. On the surface, our client code is manipulating hello, but don't forget that hello is just an interface.
Is essentially manipulating hello_stub.
Take the EJB on WebLogic as an example. The 10 classes are:
Bean class: hellobean (written by the user)
WebLogic implementation class of Bean class: hellobean_impl (generated by ejbc)
Home interface: hellohome (prepared by the user)
WebLogic implementation class (Hello bean) _ homeimpl (generated by ejbc) of the home interface)
The stub class (Hello bean) _ homeimpl_wlstub of the Weblogic implementation class of the home interface (the bytecode is dynamically generated during deployment)
The skeleton class (Hello bean) _ homeimpl_wlskeleton of the Weblogic implementation class of the home interface (dynamic generation of bytecode during deployment)
)
Remote interface: Hello (prepared by the user)
WebLogic implementation class (Hello bean) _ eoimpl (generated by ejbc) of the remote interface)
Stub (Hello bean) _ eoimpl_wlstub of the Weblogic implementation class of the remote interface (Dynamic bytecode is generated during deployment)
The skeleton class (Hello bean) _ eoimpl_wlskeleton of the Weblogic implementation class of the remote interface (dynamic generation of bytecode during deployment)
)
The client only needs the hello. Class and hellohome. class files.
(Hello home) Home = (home) (portable remote object). Narrow (CTX. Lookup ("hello"), (hello
Home). Class );
This line of code obtains the home interface from JNDI, but remember! The interface is abstract, so what kind of object instance is the home object?
What about it? It's easy to use tostring () for output. The following line shows the output result:
(Hello bean) _ homeimpl_wlstub @ 18c458
This indicates that the home object obtained from the server's JNDI tree is actually an instance of the hellobean_homeimpl_wlstub class.
The client code is as follows:
Hello H = home. Create ()
Similarly, hello is just an abstract interface. What is the H object? Print:
(Hello bean) _ eoimpl_wlstub @ 8fa0d1
It turns out to be an object instance of hellobean_eoimpl_wlstub.
This example is used to describe the EJB call process:
First, the client JNDI query, the hello name in the server's JNDI tree is actually bound to hellobean_homeimpl_wlstub, so
The server creates an object instance of hellobean_homeimpl_wlstub and serializes it and returns it to the client.
Therefore, the client obtains the home object. On the surface, the instance that obtains the hellohome interface actually performs a remote call and obtains hellobea.
N_homeimpl_wlstub class object instance. Do not forget that hellobean_homeimpl_wlstub also implements the hellohome interface.
Then home. Create () is actually hellobean_homeimpl_wlstub.create (). This method will send information to hellobean_homeim
Pl_wlskeleton, and hellobean_homeimpl_wlskeleton receives the information, and then calls the create party of hellobean_homeimpl.
So far, 1st complete RMI loops have been completed.
Note that during this RMI loop, the remote object is hellobean_homeimpl, the remote object interface is hellohome, And the stub of the object is hellohome.
Lobean_homeimpl_wlstub. the skeleton of the object is hellobean_homeimpl_wlskeleton.
Then hellobean_homeimpl calls the ejbcreate method of hellobean_impl, while the ejbcreate method of hellobean_impl will be negative
Create or assign a bean instance and create an object instance of hellobean_eoimpl_wlstub.
This step is interesting. In the previous RMI loop, the remote object hellobean_homeimpl has a proxy class hellobean_ho on the client.
Meimpl_wlstub, but in this step, hellobean_homeimpl acts as the proxy class of hellobean_impl, but hellobean _
Homeimpl is not on the client, but on the server, so RMI is not performed.
Then, the instance of the hellobean_eoimpl_wlstub object is serialized and returned to the client. This step is also interesting. The main character of the last RMI process is hello.
Bean_homeimpl and its proxy class hellobean_homeimpl_wlstub, but this time it is changed to hellobean_eoimpl and its proxy class H
Ellobean_eoimpl_wlstub.
Hello H = home. Create (); H. helloworld ();
Assume that the hello interface has a helloworld remote method. On the surface, the helloworld method of the Hello interface is called.
Use hellobean_eoimpl_wlstub's helloworld method.
Then the hellobean_eoimpl_wlstub's helloworld method will send information to hellobean_eoimpl_wlskeleton on the server, while H
After ellobean_eoimpl_wlskeleton receives the information, it calls hellobean_eoimpl's helloworld method. So far, 2nd completed
Complete RMI loop process.
Hellobean_eoimpl was called as a remote object. Its proxy class is hellobean_eoimpl_wlstub, but now hellobea
N_eoimpl is used as the proxy class of hellobean_impl. Now hellobean_eoimpl calls hellobean_impl's helloworld Method
. Note! Hellobean_impl inherits hellobean, And the helloworld method in hellobean is the code we write in person.
The code we wrote was called!
So far, an EJB call process has finally been completed. During the entire process, the main classes to be called by the server are hellobean_impl, hello
Bean? _ Homeimpl, hellobean_homeimpl_wlskeleton, hellobean_eoimpl, hellobean_eoimpl_wlskeleton. Customer
The main classes called by the user are hellobean_homeimpl_wlstub and hellobean_eoimpl_wlstub, which are not in the client code.
The class that appears in the Code is their interfaces hellohome and hello. Therefore, the client needs these two interface files, while stub is
The server sends it to them.
4. Understanding
To put it simply, it is to adapt to the needs of distributed development.
First, return to the flowchart that I finally provided.
Http://www.pbase.com/nobo123/image/27229257
The most primitive impulse on the client side must be the ability to directly call #10. userservicebean. So the first question comes,
The client and server are not in the same JVM.
This is easy to handle. Don't we have RMI? Well, this problem is solved as follows:
1. userservicebeaninterface. getuserinfo ()
2. userservicebeanstub
3. userservicebeanskeleton
4. userservicebean
The second question comes,
Userservicebean is only used by people, and is not managed. transaction logic, security logic, bean instance pooling Logic
These issues have to be considered.
OK. We want to use delegate and ejbobject to manage all these logics. Client and ejbobject, ejbobj
ECT calls userservicebean.
Note that this ejbobject is also an interface, #6. The userservice interface comes from its extends. And ejbobje
These logics managed by CT are part of the appserver.
The current process is changed:
Ejbobject
1. userservice. getuserinfo ()
2. userservicestub
3. userserviceskeleton
4. userserviceimp
5. userservicebean
This already corresponds to #6, #7, #8, #9, #10 of the entire sequence.
Can we meet our needs now? No, the third question comes again:
Since it is distributed development, I certainly have no reason to use only one specified server. I may need to use several different servers.
Ejbobject also needs to be managed.
OK. To meet your needs, we have to add another homeobject. First, it determines which server to use (of course, it is up to you to use JNDI
String). Second, it is used to manage ejbobject.
Note that this ejbhome is also an interface, #1. The userservicehome interface comes from its extends. And ejbho
Me manages the logic of ejbobject, which is also part of the appserver.
The current call order is
1. ejbhome. Create ()
2. ejbhomestub
3. ejbhomeskeleton
4. ejbhomeimp (ejswrapper)
5. ejshome
Obtain ejbobject
6. userservice. getuserinfo ()
7. userservicestub
8. userserviceskeleton
9. userserviceimp
10. userservicebean
The Calling sequence is now exactly the same as that of the flowchart.
// The basis of EJB is rmi iiop. The principle is not very difficult. The key is to make the implementation more difficult. A simple function should be implemented using 10 (or more) classes, but every one is not redundant.
// This EJB mode (or RMI) completely shields the underlying network and effectively protects the Business Code.