问题
What flaws do you see in the following design, (and what would be your ideal architecture suggestion) for a typical web 3-tier application?
My current blueprint approach is very roughly this (assuming Java, Spring, Hibernate, JSP)
Controller
Stateless, potentially wrapped with a read only transaction (to avoid lazy init exceptions), get's entities from persistence storage via the service only, passes them to the view as the model. Conducts business logic on them (should the BL be in the service layer only?), passes back to the service layer for persistence if required.
Pros: For read-only transaction wrapping - only one connection, no redundant hits for the same persistent entity, utilizes query cache better, service layer shouldn't "know" request parameters, or required init graph span, avoid lazy init exceptions.
Cons: The read-only transaction approach can be risky, controllers are not the ideal Business Logic hanging place... very hard to do JUnits (your input is a request...)
View
Non transactional (access to non lazy collections / members will result in a lazy init exception)
Pros:
The view author shouldn't affect by mere dot notation the performance of the application (e.g. cause N+1 selects due to lazy initializing a large collection.
Also in disconnected clients (Flex, or other Rich Clients) lazy initialization remotely is either non supported, or just not a smart thing to do
Cons: the controller / service / DAO must prepare carefully the right graph of entities for the view, and may be overshooting (performance) / undershooting (lazy init exception). a myriad of server side methods can cause clutter as there is a Cartesian product to the number of permutations an entity graph can be initialized
Model
Using the persistent objects as is, (no data transfer objects), state is saved in the session.
Pros: no need to rewrite POJOs, reuse of existing entities, session state is more secure than hidden fields state handling.
Cons: Bad for disconnected frameworks, risk of saving stale disconnected objects, risk of locking issues, overriding other's data, requires optimistic locking sometimes.
Service
Transactional, doesn't know the request scope, calls a DAO layer for actual persistence storage access. this is where the BL should classically be, but it seems the BL leaks to the controller side over and over.
DAO
Contains atomic persistence storage facade, ignorant of the BL, or any context
Finally, the question:
What would you fix in the above architecture?
Do you think (like me) it is a quite common approach (with some minor differences, such as open session in view, etc)? Or is it the first time you see it and I'm doing something terribly wrong (or right)?
How do you solve it in your applications? Do you use your entity POJOs also for your model and view? or do you wire it up to simpler UI beans (all fully initialized and secure)?
This may be a subjective question, but I'm sure there are clear best practice design patters that cluster to one, two or three max general "religions".
回答1:
Overall, it seems like a very good architecture. If you haven't already read it, I would recommend Martin Fowlers Patterns of Enterprise Application Architecture, which describe every subject in your question.
It is not clear from the question how large an issue you expect performance to be. In my experience, the performance bottlenecks are rarely where you think they are, and the sooner you find them, the easier it is to change the architecture to match.
You are right that testability is a major concern. I have used Martin Fowlers Passive View-pattern with some success. You should also take a look at Supervising Controller, from the same site.
回答2:
Super unless doing a SOFEA style front-end, which basically gets rid of the Controller part in the above architecture.
The front end is entirely contained on the client, which directly invokes REST or SOAP services returning JSON or XML. That seems to solve 100% of the problem with transforming domain objects for display!!!!
Perhaps, some suggest, the reason there's no clean solution to the N-tier architecture described above is because it's just plain wrong.
Links
- http://raibledesigns.com/rd/entry/sofea_also_known_as_soui
- http://www.theserverside.com/news/thread.tss?thread_id=47213
- http://wisdomofganesh.blogspot.com/2007/10/life-above-service-tier.html
My current project uses a somewhat outdated N-tier architecture with Data Transfer Objects. The DTOs are unnecessary because the application is not distributed and never will be. The one benefit (which is not worth it IMO) of using the DTOs is that it forces a clean interface for the business methods - the View components can traverse the object graph on the pseudo-models however they wish - no lazy-initialization exceptions can be thrown.
One of the architectural pain-points I see in our architecture is that the business interfaces are two damned complicated. It seems as if we need a meta-business interface to encapsulate all of the little business interfaces. Indeed, this ends up happening where one service ends up calling three other services to do its work.
The controllers (in our case, Struts 1.2 Action classes) end up calling any combination of these ultra-fine grained or coarse-grained business components. In most cases, sadly, developers unwittingly or lazily code a variety of what should be business logic in the controller classes. I scream every time I look at one of these three-hundred line Action methods!!!!
The SOFEA approach seems to offer a much cleaner approach. AJAX allows even web applications running on browsers to have their front end coded using the proper MVC pattern, which is good for both users (by offering a more dynamic UI) and developers (allowing them to code proper MVC).
The UI is completely decoupled from the reusable business logic. Is the GUI thick or thin? It really won't matter -they'll be coded in basically the same way.
SOFEA / SOUI is new to me and I've never tried it, but I've been reading about it lately and I thought I'd share my thoughts.
回答3:
Your above approach sound good.
But I think you should use UI-Beans. Of course this UI-Bean should be effectively immutable. As soon as it is created its state (and the encapsulated domain object) should not be changed.
Very simplified example:
class UIBean {
DomainObject o;
public String getDescription(){
return trimToSummaryText(o.getDescription());
}
private static String trimForSummaryText(){
....
}
}
Main pros:
- Template code tends to get cleaner and consise. Your Frontend-Developer will be happy about this.
- You don't tend to add frontend-specific helper methods to domain object classes.
- Grouping of different domain objects or view-beans is possible (ui-bean could have multiple fields). Encapsulation of lists is especially nice here.
Yes, it involves more java-classes for that. But this abstraction layer is nearly always fine as soon as your webapp and pages grow.
回答4:
Despite the question was last answered about year ago, perhaps the answer appears helpful to someone. Overall outlined by you architecture is fine, the only detail to add is: usually for passing data between layers (e.g. View and Service) instead of mentioned above UiBean-s so called DTOs (Data Transfer Objects) are used, these are plain POJOs with appropriate fields/setters/getters.
In one of previous/early versions of Java EE spec "DTO" term was mistakenly mixed with "ValueObject", though they have bit different purposes.
Hope, this helps.
来源:https://stackoverflow.com/questions/1969278/web-architecture-mvc-lazy-initialization-data-transfer-objects-open-session