palatum
CJSDN高级会员
发贴: 451
积分: 80
|
于 2003-03-17 18:57
EJB best practices: The dynamic delegate
Build more generic business delegates with Java reflection Level: Intermediate
Brett McLaughlin (brett@oreilly.com) Author and Editor, O'Reilly and Associates November 2002
While the business delegate class does bring exciting new flexibility to your enterprise Java designs, it can be tedious to code up a business delegate for every session bean in your application. In this installment of his EJB best practices series, Brett McLaughlin shows you how to create an even more generic version of the business delegate class: the dynamic delegate. In the last tip, we discussed how to use a business delegate class (not to be confused with the Business Interface pattern) to access your EJB components. By inserting a business delegate class between our client code and the EJB code, we were able to insulate our application's Web tier from both EJB semantics and business logic.
One way to look at this type of design is in terms of how generic it is. Starting with an application in which business logic and technology functions are tightly entwined, we've been gradually separating out the different layers of the application and using different techniques to alleviate their interdependency. In doing so, you should be finding that the more generic an application's underlying structure is, the more robust and maintainable it is over time.
In this tip, we'll continue working with the idea of generic design. We'll start by exploring the limits of our current business delegate implementation, then I'll show you how to overcome those limitations by creating an even more generic, and thus less rigid, implementation of the business delegate class.
The business delegate class: A refresher Recall the business delegate class for our Library bean interface we discussed last month.
Most of the LibraryDelegate class merely duplicates the methods in the original Library bean. The LibraryDelegate adds init(), destroy(), and constructor methods, and then uses these methods to delegate tasks to the Library bean. In doing so, the delegate acts as a buffer between the Web tier and your enterprise beans. Here's the original bean's business interface.
A proliferation of methods The problem with this approach doesn't become evident until you consider that many session beans have 10, 20, or more methods. In fact, it isn't uncommon to find a session bean with 50 or more methods! Because a bean's business interface must contain all the methods of the bean, so will the business delegate class. That makes for bloated code, and plenty of room for error.
Are you too quick on the keys? When working with EJB components, we're often duplicating a number of methods across remote interfaces, business interfaces, implementation classes, and now business delegates. Rather than type the methods in manually, many of us prefer to cut and paste them between editor windows and IDEs, but beware: it's just as easy to make a mistake hitting Option+V or Control+V as it is when typing methods in manually -- and the chance of error goes up as you add more methods. By double-checking that your methods are properly entered and that you've cut and pasted them as you intended to, you'll save yourself a lot of grief in the long run. In addition to bloat, we also have to consider the change factor. Because the Delegate class has to duplicate all the bean's methods, and because beans do inevitably change over time, you could find yourself spending a lot of time adding new methods to the Delegate, not to mention recompiling and, possibly, testing the new code.
By itself, this may not seem like much of a problem. But consider that we started using a business delegate class to abstract the business and presentation logic from the technology infrastructure, in this case EJB components. If changing the remote interface requires a change to the business delegate, then our business delegate is, in effect, still tied to the underlying components.
There has to be a better way, you say. And there is.
The dynamic delegate The solution is to use a dynamic delegate, which in turn uses Java reflection. Instead of having each business method hardcoded into your delegate, you can have the delegate dynamically invoke the methods (through the Java Reflection API) on the remote interface of the targeted EJB component. This allows a complete decoupling from the remote interface, in that adding a method to the business or remote interface of your beans requires no corresponding changes in the business delegate. It's also easier to make changes to your technology infrastructure with the dynamic delegate. Migrating from a remote interface and EJB technology to another technology such as Java Data Objects (JDO) would require you to change only the delegate's init() method. All the other method calls would continue to be delegated through the bean's interface, and to work with no further changes. Listing 1 shows a dynamic version of the Library business delegate:
Listing 1. A business delegate for a Library bean package com.ibm.library;
import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.rmi.RemoteException; import java.util.HashMap; import java.util.Map; import javax.ejb.CreateException; import javax.naming.NamingException;
public class LibraryDelegate implements ILibrary { private ILibrary library; private Map availableMethods;
public LibraryDelegate() { init(); }
public void init() { // Look up and obtain our session bean try { LibraryHome libraryHome = (LibraryHome)EJBHomeFactory.getInstance().lookup( "java:comp/env/ejb/LibraryHome", LibraryHome.class); library = libraryHome.create();
// Get the methods available for use in proxying availableMethods = new HashMap(); Method[] methods = ILibrary.class.getMethods(); for (int i=0; i<methods.length; i++) { availableMethods.put(methods[i].getName(), methods[i]); } } catch (NamingException e) { throw new RuntimeException(e); } catch (CreateException e) { throw new RuntimeException(e); } catch (RemoteException e) { throw new RuntimeException(e); } }
// All the hard-coded methods are removed public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
try { // See if this is init() or destroy() if (method.getName().equals("init")) { init(); return null; } else if (method.getName().equals("destroy")) { destroy(); return null; } else { Method method = (Method)availableMethods.get(method.getName());
// See if we found anything if (method != null) { return method.invoke(library, args); } else { throw new NoSuchMethodException("The Library does not " + "support the " + method.getName() +" method."); } } } catch (InvocationTargetException e) { // We don't support throwing RuntimeExceptions from EJBs // directly if (e.getTargetException() instanceof RemoteException) { throw new RuntimeException(e); } else { throw e.getTargetException(); } } }
public void destroy() { // In this case, do nothing } }
The dynamic delegate nicely solves the problem of coupling between the delegate, the bean, and its business interface. It isn't a perfect solution, however, nor is it always the best one. While you gain a tremendous amount of flexibility with this approach, you also pay a performance penalty. Java reflection isn't terribly fast, so you'll experience some lag time between calling invoke() and getting your results. The static business delegate class shown in the previous tip is a faster solution, but keeps your business and technology layers more coupled than you would like them to be. So, when weighing the two options, the choice comes down to design or performance. The dynamic delegate is the better choice when your application's design is more important than its overall performance. The business delegate is a better bet when performance is the more important factor.
You might find yourself using the dynamic delegate for intranet applications, where all the machines are on a local network and you're constantly adding or changing functionality. For e-commerce and customer-facing applications, the original business delegate is likely the better choice. In either case, you should now have a better understanding of business delegates and how they work. Play around, have fun, and I'll see you online!
|