Web
Summary:
This article will discuss how to combine several well-known frameworks for loose-coupling purposes, how to build your architecture, and how to keep your application tiers consistent. The challenge is to combine these frameworks so that each layer communicates with each other in a loosely coupled way, regardless of the underlying technology. This article will use 3 popular open source frameworks to discuss the strategy of the composite framework
In fact, even if the use of Java to build a Web application is not very cumbersome, it is not an easy thing. There are many things to consider when building a framework for an application. From a high-level perspective, developers need to consider: How to build User interface? Where does the business logic work? And how to persist the application data. Each of these three layers has their own questions to answer. What technologies should be used at all levels? How can the application be designed loosely coupled and flexible to change? Does the architecture allow layer substitution not affect other layers? How does an application handle container-level services, such as transaction processing?
When creating a framework for your Web application, there are a number of issues that need to be involved. Fortunately, many developers have already encountered such recurring problems and have established a framework to deal with such problems. A good framework has the following points: ease the burden of developers dealing with complex problems ("Do not reinvent the wheel"); internally defined as extensible; There is a strong user base support. The framework is usually a good solution to the problem on one hand. However, there are several layers of your application that may require their respective frameworks. Just as you solve your user interface (UI) problem, you should not mix transaction logic and persistence logic in. For example, you should not write JDBC code inside the controller so that it contains business logic, which is not a function that the controller should provide. It should be lightweight, and proxy calls from outside the user interface (UI) to other application tiers that serve those requests. A good framework naturally forms the guidance of how code is distributed. More importantly, the framework eases the pain of developers writing code like the persistence layer from scratch, and makes them focus on the application logic that is important to the customer.
This article will discuss how to combine several well-known frameworks for loose-coupling purposes, how to build your architecture, and how to keep your application tiers consistent. The challenge is to combine these frameworks so that each layer communicates with each other in a loosely coupled way, regardless of the underlying technology. This article will use 3 popular open source frameworks to discuss the strategy of the composite framework. The presentation layer we will use struts; the business layer we will use spring; the persistence layer uses hibrenate. You can also replace any of these frameworks in your application to get the same effect. Figure 1 shows what the top looks like when these frames are grouped together.
Figure 1 Overview of building with struts, Spring, and hibernate frameworks
Hierarchy of Applications
Most of the less complex Web applications can be divided into at least 4 accountability levels. These levels are: presentation layer, persistence layer, business layer, domain model layer. Each layer has a clear responsibility in the application and should not confuse functionality with other layers. Each application layer should be independent of each other but put a communication interface between them. Let's start with a look at each layer and discuss what these layers should provide and what they should not provide.
Performance Layer
At one end of a typical Web application is the presentation layer. Many Java developers also understand what struts offers. However, it is too common for them to put coupled code such as business logic into a org.apache.struts.Action. So let's agree on what a framework like struts should provide. Struts is responsible for this:
• Manage requests and responses for users;
• Provide a controller agent invoke business logic and other upper processing;
• Handling exceptions thrown from other layers to a struts action;
• Provide a model for display;
• Perform user interface validation.
Here are some projects that are often written in struts but should not be associated with the Struts presentation layer:
• Direct and database communications, such as JDBC calls;
• Business logic and validation related to your application;
• Business management;
• Introducing this code into the presentation layer will result in typical coupling and annoying maintenance.
Persistence Layer
At the other end of a typical Web application is a persistence layer. This is usually where things get out of hand quickly. Developers underestimate the challenge of building their own persistence-layer framework. In general, the persistence layer written internally by the organization not only requires a lot of development time, but also often lacks functionality and becomes unmanageable. There are several open source "object-relational mapping" frameworks that solve the problem very well. In particular, the Hibernate framework provides a "object-relational persistence" mechanism and a query service for Java. Hibernate has a moderate learning curve for Java developers who are already familiar with the SQL and JDBC APIs. Hibernate persistent objects are based on simple legacy Java objects and Java collections. Also, using hibernate does not prevent you from using the IDE. The following list contains the types of code you should write in a persistent layer frame:
Query-related information becomes an object. Hibernate do this through an object-oriented query language called HQL or by using conditional expression APIs. HQL is very similar to sql--just taking the table and columns in SQL instead of object and its fields. There are some new dedicated HQL language components to learn, but they are easy to understand and the documentation is doing well. HQL is a natural language used to query objects, and it can be learned at a very small cost.
Save, update, and delete information stored in the database.
The advanced object-relational mapping framework, such as hibernate, provides support for most mainstream SQL databases, which support "parent/child" relationships, transaction processing, inheritance, and polymorphism.
Here are some items that should be avoided in the persistence layer:
The business logic should be at a higher level of your application. Only data access operations are allowed in the persistence layer.
You should not mix the persistence layer logic with the logic of your presentation layer. Avoid direct communication of logic and data access in these presentation-layer components, such as JSPs or servlet-based classes. By isolating the persistence layer logic into its own layer, the application becomes easy to modify without affecting the code at the other level. For example, hebernate can be replaced by other persistence-layer frameworks or APIs without modifying code at any other level.
Business Layer
The component in the middle of a typical Web application is the business layer or service layer. From the coding point of view, this service layer is the most easily overlooked layer. It is not difficult to find this type of code scattered in the user interface layer or the persistence layer. This is not the right place because it leads to tight coupling of applications, which makes it difficult to maintain code over time. Fortunately, there are several kinds of frameworks to this problem. The two most popular frameworks in this field are spring and Picocontainer, which are called micro-containers, and you can connect your objects effortlessly without effort. All of these frameworks work in a simple concept called "Dependency Injection" (also known as "control reversal"). This article will look at spring's use of the setter injection of the bean properties for the specified configuration parameters. Spring also provides a complex form of builder injection as an alternative to setter injection. objects are connected by a simple XML file that contains references to objects such as the transaction manager, object factory, service objects that contain business logic, and data access objects.
An example will be given later in this article to give a clearer idea of how spring uses these concepts. The business layer should be responsible for the following things:
• Handle the business logic and business validation of the application;
• Management services;
• The interface for reserving and interacting with other layers;
• Manage dependencies between business-level objects;
• Increase flexibility between the presentation layer and the persistence layer so that they do not communicate directly with each other;
• Providing a context from the presentation layer to the business layer for business services;
• Manage the implementation from the business logic to the persistence layer.
Domain Model Layer
Finally, because we're talking about a not-so-complex web-based application, we need a set of objects that can move from one layer to another. The domain object layer consists of objects representing real-world business objects, such as an order, order item, product, and so on. This layer allows developers to stop creating and maintaining unnecessary data transfer objects (or DTOs) to match their domain objects. For example, Hibernate allows you to read the database information into an object graph of the domain object so that you can display the data to the UI layer when the connection is disconnected. Those objects can also be updated and sent back to the persistence layer and updated in the database. Also, you don't have to convert objects into DTOs, because DTOs move between different application layers and may be lost in the conversion. This model allows Java developers to naturally interact with an object-oriented style and object with no additional coding.
combine a simple example
Now that we have understood these components from a high level, let's start with practice. In this example, we will combine struts, Spring, and hibernate frameworks. Each of these frameworks has too many details to cover in an article. This article will show you how to combine them with a simple example code, rather than going into many details of each frame. The sample application will demonstrate how a request is serviced across each layer. A user of this sample application can save an order to the database and view an order that exists in the database. Further enhancements allow the user to update or delete an existing order.
Because the domain objects will interact with each layer, we will create them first. These objects will enable us to define what should be persisted, what business logic should be provided, and which performance interfaces should be designed. We then configure the persistence layer and define an "object-relationship" mapping for our domain object with hibernate. Then, we will define and configure our business objects. With these components, we can talk about using spring to connect these layers together. Finally, we will provide a presentation layer that knows how to communicate with the business service layer and know how to handle exceptions from other layers.
domain object Layer
Because these objects will interact with all layers, this may be a good place to start coding. This simple domain model will include an object representing an order and an object representing an order item. The order object will have a one-to-many relationship with a set of order item objects. The example code has two simple objects in the domain layer:
Com.meagle.bo.order.java: Includes an order summary information;
Com.meagle.bo.orderlineitem.java: Include details of an order;
Consider choosing a package name for your object, which will reflect how your application is layered. For example: a simple application of a domain object can be put into a com.meagle.bo package. More specialized domain objects will be placed in the com.meagle.bo below the sub-package. The business logic starts packing in the Com.meagle.service package, and the DAO object is put into the com.meagle.service.dao.hibernate package. For forms and actions, the presentation classes are put into the com.meagle.action and com.meagle.forms packages respectively. Accurate package naming provides a clear distinction between the features provided by your class, making it easier to maintain when troubleshooting, and providing consistency when adding new classes or packages to an application.
Persistence layer Configuration
There are several steps involved in setting the persistence layer with hibernate. The first step is to configure the persistence of our domain business objects. Because we work with Hibernate and POJOs for domain object persistence, all fields that are included in order and order item objects need to provide getter and setter methods. The order object will include the setter and getter methods in the standard JavaBean format for fields such as ID, user name, totals, and order items. The order item object sets the setter and getter methods for its fields in the same JavaBean format.
Hibernate maps domain objects to relational databases in an XML file. The order and order item objects will have two mapping files to represent this mapping. There are tools like Xdoclet to help with this mapping. Hibernate will map the domain objects to these files:
Order.hbm.xml
OrderLineItem.hbm.xml
You can find these generated files in the Webcontent/web-inf/classes/com/meagle/bo directory. Configure Hibernate sessionfactory to let it know which database to communicate with, which data source or connection pool to use, and which persistent objects to load. The session object provided by Sessionfactory is a translation interface between Java objects and some persistent features such as selecting, saving, updating, and deleting objects. We will discuss the Sessionfactory configuration required by the Hibernate action Session object in later sections.
Business Layer Configuration
Now that we have a domain object, we need business service objects to perform application logic, to execute calls to the persistence layer, to get requests from the user interface layer, to handle transactions, and to handle exceptions. To connect all of these together and be manageable, we'll use the bean management aspect of the spring framework. Spring uses "control reversal" or "setter Dependency Injection" to connect these objects, which are referenced in an external XML file. Control reversal is a simple concept that allows an object to accept other objects that are created at a higher level. With this approach, your object is freed from the need to create other objects and reduces object coupling.
Here is an example of an object that does not use the IOC to create its subordinate objects, which leads to tight object coupling:
Figure 2: An object organization that does not use IOC. Object A creates objects B and C.
Here is an example of using the IOC, which allows objects to be created and passed on to other objects at a higher level, so that other objects can directly use ready-made objects [: The other object does not have to create the objects that are to be used personally:
Figure 3: Objects using the IOC organization. Object A contains setter methods, which accept interfaces to Objects B and C. This can also be done using the builder in object A, B and C.
Set up our business service target
We will accept interfaces in the setter methods used in our business objects that allow loosely defined implementations of objects that will be set or injected. In our case we will allow our business service object to accept a DAO to control the persistence of our domain objects. When we use hibernate in the example of this article, we can easily switch to a different implementation of the persistence framework, informing spring of using the new implemented DAO object. You can understand how programming to interfaces and using the "Dependency injection" pattern is loosely coupled to your business logic and your persistence mechanism.
Here is the interface of the business service object, which is the pile that the DAO object relies on.
Public interface IOrderService { public abstract Order Saveneworder (order) Throws Orderexception, Orderminimumamountexception; Public abstract List Findorderbyuser (String user) Throws Orderexception; public abstract order Findorderbyid (int id) Throws Orderexception; public abstract void Setorderdao (Iorderdao Orderdao); } |
Note that the above code has a setter method prepared for the DAO object. There is no Getorderdao method because it is not necessary because there is no need to access the attached Orderdao object from the outside. DAO objects will be used to communicate with our persistence layer. We will use spring to connect Business service objects with DAO objects. Because we encode to the interface, we do not tighten the coupling implementation.
The next step is to write our DAO implementation object. Because spring has built-in support for Hibernate, this example DAO will inherit the Hibernatedaosupport class, which makes it easy to get a reference to the Hibernatetemplate class, Hibernatetemplate is a helper class that simplifies the encoding and processing of hibernate session hibernateexceptions. Here is the DAO Interface:
Public interface Iorderdao { public abstract order Findorderbyid (final int id); Public abstract List Findordersplacebyuser (final String placedby); public abstract Order Saveorder (final order); } |
We have two more objects to connect with our business tier. This includes hibernatesessionfactory and a TransactionManager object. This is done directly in the spring configuration file. Spring provides a hibernatetransactionmanager that will bind a hibernate session to a thread from the factory to support the transaction. Here is the spring configuration for Hibernatesessionfactory and Hibernatetransactionmanager.
<bean id= "Mysessionfactory" Class= "Org.springframework.orm.hibernate. Localsessionfactorybean "> <property name= "Mappingresources" <list> <value> Com/meagle/bo/order.hbm.xml </value> <value> Com/meagle/bo/orderlineitem.hbm.xml </value> </list> </property> <property name= "Hibernateproperties" <props> <prop key= "Hibernate.dialect" Net.sf.hibernate.dialect.MySQLDialect </prop> <prop key= "Hibernate.show_sql" False </prop> <prop key= "Hibernate.proxool.xml" C:/mywebapps/.../web-inf/proxool.xml </prop> <prop key= "Hibernate.proxool.pool_alias" Spring </prop> </props> </property> </bean> !--Transaction Manager for a single Hibernate Sessionfactory (alternative to JTA)--> <bean id= "Mytransactionmanager" class= "org. Springframework. Orm. Hibernate. Hibernatetransactionmanager "> <property name= "Sessionfactory" <ref local= "Mysessionfactory"/> </property> </bean> |
Each object can be referenced by a <bean> tag in the spring configuration. In this example, the Bean "Mysessionfactory" represents a Hibernatesessionfactory,bean "Mytransactionmanager" representing a hibernate transaction Manager Note that the Transactionmanger bean has an attribute element called Sessionfactory. Hibernatetransactionmanager has a setter and getter method prepared for Sessionfactory, which is used for dependency injection when the spring container is started. The Sessionfactory property references the Mysessionfactory bean. These two objects are now joined together when the spring container is initialized. This connection frees you from creating singleton objects and factories for referencing and creating these objects, which reduces code maintenance in your application. The mysessionfactory bean has two attribute elements, which are translated into setter methods prepared by Mappingresources and hibernatepropertes. Typically, if you use hibernate outside of spring, this configuration will be saved in the Hibernate.cfg.xml file. In any case, spring provides a convenient way to merge the hibernate configuration in the spring configuration file.
Now that we have configured our container services beans and connected them together, we need to connect our business service objects with our DAO objects. Then, we need to connect these objects to the transaction manager.
This is what it looks like in the spring configuration file:
!--Order SERVICE--> <bean id= "OrderService" class= "org. Springframework. Transaction. Interceptor. Transactionproxyfactorybean "> <property name= "TransactionManager" <ref local= "Mytransactionmanager"/> </property> <property name= "target" > <ref local= "Ordertarget"/> </property> <property name= "Transactionattributes" <props> <prop key= "find*" Propagation_required,readonly,-orderexception </prop> <prop key= "save*" Propagation_required,-orderexception </prop> </props> </property> </bean> !--order TARGET PRIMARY BUSINESS OBJECT: Hibernate Implementation--> <bean id= "Ordertarget" Class= "com. Meagle. Service. Spring. Orderservicespringimpl "> <property name= "Orderdao" <ref local= "Orderdao"/> </property> </bean> !--Order DAO OBJECT--> <bean id= "Orderdao" Class= "com. Meagle. Service. Dao. Hibernate. Orderhibernatedao "> <property name= "Sessionfactory" <ref local= "Mysessionfactory"/> </property> </bean> |
Figure 4 is an overview of what we have connected together. It shows how each object is related and how it is set by spring into other objects. Compare this picture with the spring configuration file in the example application to see the relationship between them.
Figure 4: This is how spring will assemble the beans on the basis of this configuration.
This example uses a Transactionproxyfactorybean, which has a setter method that is prepared for the transaction manager we have defined. This is a useful object that knows how to handle declared transaction operations and your service objects. You can define how transactions are handled by the Transactionattributes attribute, and the Transactionattributes attribute defines the schema for the method name and how they participate in a transaction.
The Transactionproxyfactorybean class also has a setter,target for a target that will be a reference to our business service object called Ordertarget. The Ordertarget Bean defines which business service object to use and has a property that points to Setorderdao (). The Orderdao Bean will reside in this property, and the Orderdao bean is our DAO object that communicates with the persistence layer.
And one more note about spring and beans is that beans work in two different modes. Both of these patterns are defined as singleton and prototype. The default pattern for a bean is singleton, which means that an instance of a shared bean is managed. This is for stateless operations-like a stateless session bean will provide. When the bean is provided by spring, the prototype mode allows a new instance of the bean to be created. You should use the prototype mode only if each user needs copies of their own beans.
mentioning for a service locator
Now that we have connected our services to our DAO, we need to expose our services to other layers. This service is typically used as code in a user interface layer, such as struts or swing. A simple approach is to use a class of service locator patterns to return resources from a spring context. This can also be done directly by referencing the bean ID through spring.
Here is an example of how to configure a service locator in the Struts action:
Public abstract class Baseaction extends Action { Private IOrderService OrderService; public void Setservlet (Actionservlet Actionservlet) { Super.setservlet (Actionservlet); ServletContext ServletContext = Actionservlet.getservletcontext (); Webapplicationcontext WAC = Webapplicationcontextutils. Getrequiredwebapplicationcontext ( ServletContext); This.orderservice = (iorderservice) Wac.getbean ("OrderService"); } Protected IOrderService Getorderservice () { return orderservice; } } |
user interface Layer configuration
The user interface layer for the example application uses the Struts framework. Here we will discuss the part that is related to struts when applied to a hierarchy. Let's start by checking an action configuration in the Struts-config.xml file.
Type= "Com.meagle.action.SaveOrderAction" Name= "OrderForm" Scope= "Request" Validate= "true" Input= "/neworder.jsp" > Save New Order Path= "/neworder.jsp" Scope= "Request" Type= "Com.meagle.exception.OrderException"/> Path= "/neworder.jsp" Scope= "Request" Type= "com. Meagle. exception. Orderminimumamountexception "/>
|
The Saveneworder action is used to persist an order that a user submits from the user interface layer. This is a typical struts action; However, note the exception configuration for this action. These exceptions are also configured in the spring configuration file for our business service objects. When these exceptions are thrown from the business layer we can handle them appropriately in our user interface. The first exception, Orderexception, is used by this action when the order object has failed to be saved in the persistence layer. This causes a transaction rollback and passes the exception back to the struts layer through the business object pass. Orderminimumamountexception, a transaction in the business object logic fails because the submitted order does not reach the minimum order quantity. The transaction then rolls back and the exception can be properly handled by the user interface layer.
The final connection step is to enable our presentation layer to interact with our business layer. This has been done by using the service locator discussed earlier. The service layer acts as an interface to our business logic and persistence layer. Here's the Saveneworder action in struts. How can you invoke a business method using a service locator:
public Actionforward Execute ( actionmapping mapping, actionform form, Javax.servlet.http.HttpServletRequest request, Javax.servlet.http.HttpServletResponse response) throws java.lang.Exception { OrderForm oform = (orderform) Form; //Use the ' form ' to ' build ' order object ' //CAN Be saved in the persistence layer. //The full source code in the sample app. //Obtain the Wired Business service object //from the Servic E Locator Configuration //in baseaction. //Delegate the "Save to" service layer and //further upstream To save the order object. Getorderservice (). Saveneworder (order); Oform.setorder (order); Actionmessages messages = new Actionmessages (); Messages.add ( Actionmessages.global_message, New Actionmessage ( "message.order.saved.successfully") )); Savemessages (request, messages); Return Mapping.findforward ("Success"); } |
Conclusions
This article covers a number of topics in terms of technology and architecture. The main idea out of it is how to better tier your applications: User interface layer, persistent logic layer, and any other application layer you need. This allows you to decouple your code, allowing you to add new code components to make your application easier to maintain in the future. The technology covered here is a good solution to this kind of problem. In any case, using such a framework allows you to replace the current layer with other technologies. For example, you may not want to use hibernate persistence. Because you encode the interface into your DAO object, how can you use other techniques or frameworks, such as IBATIS, as an alternative is obvious. Or you might replace your UI layer with a frame that is different from struts. Changing the implementation of the UI layer does not directly affect your business logic layer or your persistence layer. Replacing your persistence layer does not affect your UI logic or the business services layer. Integrating a Web application is not a trivial task, it can be easier to handle by decoupling your application layers and composing them with the right framework.