As previously discussed in many EJB resources, anEJBObject is an object that represents a client's view of the Enterprise Java Bean. It is generated by the container provider. A client never references an ejb bean instance directly, but rather references theEJBObject which implements the bean remote interface. The EJBHome object is very similar to EJBObject in the sense that it is also generated by the container. Also, it implements the bean's home interface, which is defined by the bean provider. Rather than implementing business logic, however, it provides life-cycle operations on the enteprise beans.
EJBObject is more of an abstract idea than a physical implementation. So far, we know that clients are given a remote handle to EJBObjects, but how is the EJBObject physically implemented on the server side? Well, it is not implemented at all !
Most EJB servers that are available today are literally implementing the EJB specification. That is, for each logical EJBObject there is one physical EJBObject that receives requests.
This approach is very naive and may easily lead to scalability problems if there are many EJBObjects alive at any one time. In addition, this gives a rather complex structure to the EJB container.
For example, one can have a finder method that returns an enumeration of 1.000.000 EJBObjects. Does this mean that we now have to create 1.000.000 server EJBObject counterparts? This would be a serious resource drain !
In JBoss there is only one physical EJBObject that serves all logical EJBObjects. That physical EJBObject is Container. For each EJB type there is one container object, which plays the role of EJBObject by wrapping all instances of a particular EJB type.
JBoss' approach is superior in many aspects, and it simplifies the container architecture immensely. Clients, however, never notice this. They have something that looks and feels like a real server EJBObject, but this is merely an illusion. Behind the scenes there is only one object (Container) handling all method invocations. The final result is full EJBObject conformity.
JBoss's client objects (EJBObject andEJBHome) are constructed as dynamic proxies. But before we investigate dynamic proxies, it is important to notice that there are two different implementations of dynamic proxies, that are in fact almost totally the same. The package jrmp13.interfaces* contains default implementation ofEJBObject proxies that utilizes the core java.lang.reflect package of j2se 1.3. In contrast, the package jrmp12.interfaces* containsEJBObjects proxies that are using JBoss's home brewed proxy framework of j2se 1.2. This package is primarly intended to serve for "history proofing" of JBoss (i.e., enabling JBoss to be used with j2se 1.2 version).
*Full package names are:
org.jboss.ejb.plugins.jrmp13.interfaces
org.jboss.ejb.plugins.jrmp12.interfaces
The ContainerInvoker component, which we will focus on in detail later, is responsible for maintaining EJBObject andEJBHome. A closer look at ContainerInvoker reveals an interface for obtaining these objects. Dynamic proxies of EJBObject andEJBHome are created inJRMPContainerInvoker, a default implementation of the ContainerInvokerinterface.
A dynamic proxy is an object that implements a list of interfaces specified at runtime when the object is created. A proxy interface is an interface that is implemented by a proxy class. Each proxy class instance has an associated invocation handler object, which implements the interface InvocationHandler.
EJBObject and EJHome object are created by following classical proxy instantiation technique:
Proxy.newProxyInstance(bean.getRemoteClass().getClassLoader(), new Class[] { bean.getRemoteClass() }, new EntityProxy());*
*Not exactly as is, simplified to a certain degree
In this particular case, given the classloader that loaded the entity bean's remote interface, its Class class, and the invocation handler (EntityProxy), we are able to create a new Proxy instance which implements the bean's remote interface. Sincejava.lang.reflect.Proxy class is serializible, it can be sent to the remote client across the network.
The remote client, having a dynamic proxy class that implements the bean's remote interface, dispatches all method invocation on that interface to the instance of the underlying invocation handler.
Depending on the type of the EJB bean on the server, there are four proxy classes: EntityProxy,HomeProxy,StatelessSessionProxy and StatefulSessionProxy.
All four proxies implement thejava.lang.reflect.InvocationHandler interface and also subclass GenericProxy, which in turn contains a stub of the ContainerRemote interface implementor from the server side. That implementor is JRMPContainerInvoker.
Each of the proxy classes implements the only method defined in the InvocationHandler interface: invoke. The invoke method intercepts all calls to the EJB remote interface (client side) and depending on the particular type of EJB method, does one of the following:
- handles the method locally in the Proxy class - passes the method call accross the wire to the remote EJB container - invokes the method in the local EJB container
This design of client objects gives maximum flexibility in the following sense: all calls that can be handled by clients themselves are handled locally, preventing the roundtrip across the wire and saving the container from unneccessary loading. Calls coming from other EJBs, but local to the JVM, are also optimized since they bypass the network transport layer and call the specific underlying container directly. Finally, only calls that absolutely must leave the local VM are passed across the wire.
Let's trace the remote call on busines method B of an entity bean.
First, the method call goes on the proxy interface where it is dispatched to its invocation handler, which in this case is EntityProxy. Entity proxy converts the call into aRemoteMethodInvocationobject and stuffs it into a MarshalledObject. Using a stub of theJRMPContainerInvoker, the remote call is sent over the "wire" to the server'sJRMPContainerInvoker object where it is unpacked from MarshalledObject and handed off to the container.
*Note that, since the jdk1.2 release, skeletons are avoided on the server side. Consult RMI specification for more info.
Наши друзья |