I l @ ve RuBoard |
Application design is the first step in J2EE application development, as any text on the topic will attest. The reason for this is simple: changing the design is usually much more expensive than adding a new feature, or fixing a bug in the application. Design of the EJBs will also significantly impact the performance of a J2EE application. 2.1.1 Know When to Use EJBsEven though EJBs are great, they are not always the right solution to the problem at hand. Developers often refer to this as "using a sledgehammer to crack a nut." Whenever you are considering how to implement your application, bear in mind the following basic guidelines:
In general, deciding whether EJBs are the right choice for your application comes from experience. Knowing exactly what you will gain and what you will lose by using EJBs will also help you make the right decision. 2.1.2 Use Standard Design ArchitectureAs I mentioned earlier, it is usually a good idea to design most of the application before implementing it. This is especially true of J2EE applications, which regularly contain many different components . Even though every developer or system architect has a unique approach to application design, most people follow some general principles. The first of these principles is the layered structure of a J2EE application:
These layers are by no means set in stone. You might encounter a situation in which adding an additional logical layer will make the application design cleaner and easier to implement. Or you might find that you don't need a presentation layer if your application is used by another application. In any case, the layout of an application is flexible, but there are some definite advantages to using this three-layer structure, given that the J2EE specification encourages it by classloader schemes and packaging rules. Also, different types of components that can be built in J2EE (servlets, entity beans, session beans, etc.) lend themselves to this type of structure. The second principle of design has to do with the order in which the application layers are developed. Even though every programmer has his own philosophy and way of developing an application, you should follow these rules if you follow the layout described earlier:
2.1.3 Use CMP Entity BeansWhenever possible, try to use container-managed persistence (CMP) for entity beans. Most application servers have highly optimized handling mechanisms for CMP beans, and even though CMP beans might be a little harder to configure and deploy properly, they are well worth the effort. Some of the benefits of CMP are:
2.1.4 Use Design PatternsLearn and use as many EJB design patterns as possible. Most patterns will save you development time, improve the performance of your application, and make it more maintainable . It's fair to say that without patterns, writing solid J2EE applications would be very hard. Because this is not a design patterns book, we will not examine in detail the multitude of EJB patterns that exist out there. Instead, we'll focus on several patterns that most EJB developers will find useful in their work. 2.1.4.1 Session fa §adeA session fa §ade is the most frequently used EJB design pattern. It's a way to encapsulate business workflow logic to get better performance and to have more maintainable code. The basic idea is very simple: put all business workflow logic into stateless session beans, and have clients call those beans instead of calling the different components of the application. This concept is shown in Figure 2-1. Figure 2-1. Session fa §ade patternThere are many advantages to this pattern. The most significant is that moving all business logic into its own layer makes the code a lot cleaner and more manageable. Because each workflow operation corresponds to one business method in the session bean, all implementation logic for that operation is executed under one transaction. This means you need to set the transaction attributes for the session bean methods to "Required" for this aspect of the fa §ade to work correctly. Having session fa §ades will also enable you to use local interfaces in the persistence layer, and expose only the remote session bean interface to the client. 2.1.4.2 Value objectsValue objects , or data transfer objects, are a way to transfer "bulk" data between remote components, with minimal network traffic. For example, suppose you have a User entity bean. To get the user's first name, last name , address, and other data, you would usually have to call a get method for each piece of data that you need. If you have to do this through a remote interface, the network overhead will be very large. The natural solution to this problem is to create an object that can hold all the data you need, and use that object to transfer the data. This is exactly what a value object is. Figure 2-2 illustrates this pattern. Figure 2-2. Value object patternA common practice is to use the value object in the entity bean, instead of constructing it every time a client requests it. Another common practice is to expose several different value objects from a single entity bean so that clients can get only the data they are interested in. This is ordinarily used when the entity bean contains large amounts of data, and sending everything over the network becomes impractical . When the number of value objects is very large and their management becomes tedious , it might be a good idea to implement a generic HashMap value object that can be used to transfer arbitrary data. Now, a generic value object would have only a couple of getField / setField methods, and it would be hard to implement some kind of validation code to ensure that the right value object fields are being set. In contrast, a simple value object has getXXX / setXXX methods for each field, which makes it impossible to make that mistake. A compromise is to implement all value objects as interfaces, and then use a DynamicProxy with a HashMap to store the value object fields. Example 2-1 shows a dynamic proxy implementation, and how it's used in an entity bean. Example 2-1. Use of a dynamic proxy implementation in an entity beanpublic class ValueObjectProxy implements InvocationHandler, Serializable { protected HashMap fieldMap; protected Class valueObjectClass; protected ValueObjectProxy (Class valueObjectClass) { this.valueObjectClass = valueObjectClass; fieldMap = new HashMap( ); } public static Object createValueObject (Class valueObjectClass) { return Proxy.newProxyInstance ( valueObjectClass.getClassLoader( ), new Class[ ] {valueObjectClass}, new ValueObjectProxy(valueObjectClass)); } public Object invoke (Object proxy, Method method, Object[ ] args) throws Exception { String methodName = method.getName( ); if (methodName.startsWith ("get")) { // Remove "get" to get the field name. String fieldName = methodName.substring(3); // It's a get, so return the value. if (!fieldMap.containsKey ("fieldName")) throw new ValueObjectException ("Field " + fieldName + " does not exist"); return fieldMap.get(fieldName); } else if (methodName.startsWith ("set")) { // Remove "set" to get the field name. String fieldName = methodName.substring(3); // Put it into the hashmap. // Assume we received one argument in the set method. fieldMap.put (fieldName, args[0]); // It's neither a get nor a set. } else { throw ValueObjectException ("Invalid method"); } } } public SomeBean implements EntityBean { // Skipping irrelevant methods . . . public SomeValueObject getValueObject( ) { // Create the value object. SomeValueObject vo = (SomeValueObject) ValueObjectProxy.createValueObject (SomeValueObject.class); // Set its values. vo.setName ("John Smith"); vo.setAddress ("140 Maple Drive"); return vo; } } Because local interfaces are implemented in EJB 2.0, there is really no need to expose entity beans with remote interfaces. However, you still need to handle domain objects, such as the User object in the example, whether the entity bean is directly available to the client or not. So, in this case, you still have to use value objects in to transfer this data between application layers. |
I l @ ve RuBoard |