J2EE模式一瞥(3)
2002.10
www.theserverside.com,网站,我想做J2EE的人都知道,是一个很棒的地方。如果您还不知道这个地方,还不赶快去?
最近,该网站推出A Look Inside J2EE Patterns,系列文章,个人认为蛮不错的,而且很成体系,所以萌生了翻译、整理成中文的念头。
第三天:
A thick smog had descended upon downtown Manhattan on the third day of J2EE Patterns. I hailed a cab which scooted me down through a labyrinth of morning traffic to the financial district. Yesterday's lesson was still fresh in my mind. I felt like a conglomerate of attributes, having been 'stuffed' into the cab, my conveyence, my DTO. I dropped the driver a five, and entered the building, but before I could get to the elevators, I had to show some ID at a security checkpoint. Although they had seen me yesterday and the day before, they still had to 'validate' me. Increased security was still prevalent throughout the city. Verifying my identity was a daily task for these people. As far as they were concerned, my identity became 'stale' on a daily basis.
The coffee was out in full force this morning as some people were up late watching post season baseball and had to catch an early morning train to be at class. Yet people were still alert, asking a myriad of technical questions in reference to the slides and labs.
As a lead into the next section, Owen reiterated yesterday's lesson on Domain and Custom DTOs by mentioning their drawbacks. Domain and Custom DTOs tightly couple the client to the system in that the client is burdened with the need to identify and properly construct DTO types, especially when there are a multitude of domain objects. The number of DTOs can get quite large especially when using Custom DTOs. The solution to this problem is to use Generic DTOs, of which there are two types: Hashmap and Rowset.
Generic DTOs: Hashmap and Rowset Rowset其实蛮好用的。
One way to reduce the number of DTO types is to implement a Hashmap DTO which enables the storage of any Java Object type identified by an attribute key. The client creates a Hashmap and stuffs it with name value pairs and passes it as a parameter to an EJB. The Typed Hashmap is an extension of this pattern; it includes and wraps the HashMap with a type-checking class that will enforce that only the originally inserted types and keys are allowed. By 'hardening' the object types and keys, you ensure the Typed Hashmap ensures that they remain constant.
The Rowset DTO pattern is appropriate whenever data is accessed through JDBC and large ResultSets are returned. You can use a java.sql.RowSet object to encapsulate the rows retrieved from your table. In a nutshell, the RowSet object is simply a ResultSet object that functions as a JavaBeans component.
A gentleman from the back of the room, with a slight English accent asked Owen a question, but wasn't sure if he was correctly pronouncing his name.
"Oh don't worry about it," Owen assured him, "I had a Russian teacher once who used to call me Oven." The class had a good laugh at this.
The question he asked, with reference to the RowSet DTO Pattern, was how one can ensure that when two clients are looking at the same row, that that data doesn't become stale.
"We're just getting to that," responded Owen. "Your question is a great segway into our next topic: the DTO Version Number Pattern."
The DTO Version Number Pattern
The DTO Version Number pattern solves the problem of data becoming stale when two clients are reading and updating the same data. The solution is to use Version Numbers to implement staleness checks on Entity Beans. The Version Numbers confirm that the data in memory is the same as the version in the database. Version numbers are added to the DTOs, the Entity Beans and the Database tables.
In the DTO version number lab, we were presented with a scenario where whenever two clients tried to update a field from the same entity bean, only one client's changes were committed. The DTOs sent to the clients were inside of separate transactions so that when the first client updated the data, the second client had no knowledge of these updates and was now working with a stale DTO. The lab required solving the classic 'readers-writers' problem. Some validation logic also had to be added to the DTOs as these were part of the lab requirements, since many of the clients were entering invalid data.
At the end of the lab, Owen asked the class why we used a Custom DTO in the lab instead of Domain DTOs. Custom DTOs reduce latency. But Domain DTOs might be more useful if you have many usecases. It all depends on the immediate and future needs of the system.
The Session Facade
Before lunch, Owen started lecturing on the pattern that he described as the "grand daddy of them all": The Session Facade Pattern.
"You've already been using the Session Facade in every lab we've touched, except the JDO one. A 'facade' is when you simplify a complex system," Owen explained. So in effect, the class had already been using 'facades' by creating layers of abstraction that hide underlying complexity.
The more general Facade Pattern serves to cleanly separate the Logic and Data Layers. The principle behind the Session Facade, a specialization of the Facade Pattern, is to achieve the maximum reuse of Business Logic and Data. The Session Facade decouples persistence code from business logic.
By implementing the Session Facade Pattern, reusability is improved because data components no longer encapsulate application specific logic and are now useful accross applications. This reduces 'code bloat' in entity beans, which really should only represent business data. Conversely, your business logic can now also be applied to various data components.
"Entity beans are designed to be shared between different processes. We discourage the use of any business methods in your entity bean layer," Owen responded to a question on whether entity beans should or shouldn't contain business methods.
Reducing network overhead is another benefit of this pattern. The EJB client can execute a use case's business logic in one transaction and one bulk call, instead of having to deal directly with a multitude of entity beans, possibly accross a network. The client really should only have a single point of entry into the system. Owen showed us an antipattern sequence diagram of an EJB client talking directly with the entity layer which helped to reinforce the idea of using the Session Facade to reduce network overhead.
The gentleman from the back of the room asked why we couldn't simply use a plain Java class to front our entity beans. Owen reminded him that the Session bean embodies all the services the container offers such as transactions. Transactions should be handled by the container and not programmatically.
Just before we were dismissed to sate our appetites at one of the many fine New York restaurants in the vicinity, somebody asked whether it's worth refactoring his system to use session beans and entity beans. His company is currently using plain old Java objects with TopLink. A brief discussion ensued and another student answered that it's always good to refactor your code. Owen said that it's worth refactoring if you plan on reusing your code.
After lunch, we finished off the Session Pattern and looked at an interesting variation of it: The Message Facade, which is an asynchronous form the Session Facade. The benefits of it are similar: reduced network overhead, increased scalability, with the addition of decreased response times for the client, and client independent transaction semantics. As an example we looked at a web-based airline reservation system, which, given the nature of the airline industry, cannot make clients wait as it sometimes takes days for a response. Somebody asked which commercial systems are using JMS and one gentleman, who works for a pharmaceutical firm, said that his company uses it. Clients, such as researchers and doctors, submit large protein strings which are parsed and sent out to different J2EE applications for asynchronous processing. Owen mentioned that many projects he's done for financial institutions have implemented JMS technology.
The Command Pattern
Towards mid-afternoon, we began our study of the Command Pattern. So far, we had learned how to encapsulate data in a Data Transfer Object. The Command Pattern uses a similar strategy, except it encapsulates a request object into a Command Bean, which the client sets the attributes on. The client then simply calls the executeCommand() method which transparently uses some routing logic to get to the destination EJB. The routing logic then sends the Command Bean to a CommandServer (a CommandServerBean), which invokes the execute() method of the Command Bean. All business logic is written in the execute() method of the Command Bean, which is implemented from an abstract Command interface.
The Command Pattern decouples the client from EJBs. For instance, servlets that need to invoke business logic no longer need to know about the methods required to interact with the Session Bean layer. The CommandServer and routing logic code are reusable across applications. The Command Bean is also reusable in non-EJB environments. The essential benefit of this pattern is the decoupling of the presentation layer from server side components.
A further variation of this pattern was the Data Access Command bean, which helps to decouple business logic from the persistance mechanism. The Data Access command bean encapsulates persistance logic (getting connections, using prepared statements, all JDBC code, etc.).
Service Locator (EJBHomeFactory)
We finished off the third day by looking at the Service Locator, or EJBHomeFactory Pattern. JNDI lookup calls from the client are expensive operations with signifigant performance overheads. The Service Locator solves this problem by abstracting EJB Home lookup code into a reusable Java Class. It obtains home stubs from the JNDI on initial client requests, and caches them for all subsequent requests, which results in significant performance gains.
Moving Into the Web Tier
On the fourth day of J2EE Patterns, our journey continues through the Business tier and onwards into the Web tier. Day 4 will be an interesting class, with the morning spent discussing The Business Delegate Pattern and MVC architecture. We then move on to J2EE Web Patterns and the Struts Framework.