This article will discuss how to combine several famous frameworks for loose coupling, how to build your architecture, and how to align your application layers. 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, it's not easy to build a Web application that's not very cumbersome, even with Java. There are many things to consider when building a framework for an application. From the top, developers need to consider: How to create a user interface? Where do you handle business logic? And how to persist application data. Each of these three layers has their own questions to answer. What technologies should be used at each level? How can the application be designed loosely coupled and flexibly changed? Does the schema allow the substitution of layers to affect other layers? How does an application handle container-level services, such as transaction processing?
When creating a schema for your Web application, there are quite a few issues to be involved. Fortunately, many developers have already encountered such recurring problems and have established a framework for dealing with such problems. A good framework has the following: Mitigating 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 tiers of your application that may require their respective frameworks. As with solving your user interface (UI) problems, you should not be doped with transactional logic and persistent logic. For example, you should not write the JDBC code inside the controller so that it contains the business logic, which is not the function that the controller should provide. It should be lightweight and proxy requests from outside the user interface (UI) to other application tiers that serve these requests. A good frame naturally forms the guide to how the code is distributed. More importantly, the framework eases the pain of developers writing code like the persistence layer from scratch, allowing them to focus on application logic that is important to their customers.
This article will discuss how to combine several famous frameworks for loose coupling, how to build your architecture, and how to align your application layers. 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 frames in your application to get the same effect. Figure 1 shows what it looks like from the top when the frames are grouped together.
Figure 1 Overview built with struts, Spring, and hibernate frameworks
Layering of applications
Most non-complex web applications can be divided into at least 4 accountability levels. These levels are: The presentation layer, the persistence layer, the business layer, the domain model layer. Each layer has a clear responsibility in the application and should not be confused with other layers. Each application layer should be independent of each other but to put a communication interface between them. Let's start with a look at each layer and discuss what these layers should offer and what should not be provided.
Presentation Layer
At one end of a typical Web application is the presentation layer. Many Java developers also understand what struts has to offer. However, it is too common for them to put a coupling code like business logic into a org.apache.struts.Action. So let's agree on what a framework like struts should provide. Here's what struts is responsible for:
Manage requests and responses for users;
Provides a controller proxy to invoke business logic and other upper processing;
Handles the exception thrown from another layer to a struts action;
Provide a model for the display;
Performs user interface validation.
Here are some items that are often written in struts but should not accompany the struts presentation:
Direct and database communication, such as JDBC call;
Business logic and validation related to your application;
Transaction management;
Introducing this code into the presentation layer will lead to typical coupling and annoying maintenance.
Persistence layer
At the other end of a typical Web application is the persistence layer. This is usually the place where things get out of control quickly. Developers underestimate the challenge of building their own persistence layer framework. In general, the persistence layer written by the organization itself requires not only 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. In particular, the Hibernate framework provides the "Object-relational persistence" mechanism and query services for Java. Hibernate has a modest learning curve for Java developers who are already familiar with SQL and JDBC APIs. Hibernate persistent objects are based on simple legacy Java objects and Java collections. In addition, using hibernate does not hinder the IDE you are using. The following list contains the types of code you should write in a persistent layer framework:
Query-related information becomes an object. Hibernate does this through an object-oriented query language called HQL or by using the conditional expression API. The HQL is very similar to sql--just replacing the table and columns in SQL with object and its fields. There are some new specialized HQL language components to learn, but they are easy to understand and document well done. HQL is a natural language used to query objects, and it takes a small price to learn it.
Save, update, and delete information stored in the database.
Advanced Object-Relational mapping frameworks like Hibernate provide 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 in 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 like JSPs or servlet-based classes. By isolating the persistent layer logic into its own layer, the application becomes easy to modify without affecting the code in the other layers. For example, hebernate can be replaced by other persistent layer frameworks or APIs without modifying the code at any other layer.
Business Layer
The components in the middle of a typical Web application are the business layer or the service layer. From the point of view of coding, 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 in the persistence layer. This is not the right place, as this leads to tight coupling of the application, so that the code will be difficult to maintain over time. Fortunately, there are several kinds of frameworks for this problem. The two most popular frameworks in this area are spring and Picocontainer, which are called micro-containers, and you can easily and effortlessly connect your objects together. All of these frameworks work in a simple concept called "Dependency Injection" (also known as "inversion of Control"). This article will look at the use of spring's setter injection for the specified configuration parameters through the Bean property. Spring also provides a complex form of builder injection as an alternative to setter injection. Objects are joined together by a simple XML file that contains references to objects such as transaction managers, object factories, service objects that contain business logic, and data access objects.
Later in this article, we will use examples to make it clearer how spring uses these concepts. The business layer should be responsible for these things:
Handle the business logic and business validation of the application;
Management services;
An interface for reserving and interacting with other layers;
Manage dependencies between business-level objects;
Increased flexibility between the presentation layer and the persistence layer so that they do not communicate directly;
Provide a context from the presentation layer to the business layer to obtain 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 between different tiers. The domain object layer consists of objects that represent the business objects in the real world, such as: an order, an order item, a product, and so on. This layer allows developers to stop building and maintaining unnecessary data transfer objects (or called DTOs) to match their domain objects. For example, Hibernate allows you to read database information into an object graph of a domain object so that you can display the data to the UI layer when the connection is broken. 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 tiers and may be lost in conversions. This model allows Java developers to naturally interact with an object-oriented style and object with no additional coding.
To combine a simple example
Now that we have understood these components from a high level, let's start with the practice. In this example, we will merge struts, Spring, and hibernate frameworks. Each of these frames has too much detail to cover in an article. This article will use a simple example code to show how to combine them, rather than entering into the 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 into the database and view an order that exists in the database. Further enhancements enable users to update or delete an existing order.
Because 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 will then configure the persistence layer and use Hibernate to define the object-relationship mappings for our domain objects. We will then define and configure our business objects. With these components in place, we can discuss the use of 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 the anomalies that arise 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 at the domain level:
Com.meagle.bo.Order.java: Includes an overview of the order;
Com.meagle.bo.OrderLineItem.java: Includes details of an order;
Consider choosing the package name for your object, which will reflect how your application is layered. For example, a simple application domain object can be put into a com.meagle.bo package. More specialized domain objects will be placed in the sub-packages below the Com.meagle.bo. 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. The performance classes for forms and actions are put into 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 failure is maintained, and providing consistency when new classes or packages are added to the application.
Persistence Layer Configuration
Setting up a persistence layer with hibernate involves several steps. The first step is to configure the persistence of our domain business objects. Because we work with Hibernate and POJOs for domain object persistence, both the order and order item objects include all fields that need to provide getter and setter methods. The order object will include the setter and getter methods for the standard JavaBean format, such as ID, username, totals, and order items. The order item object sets the setter and getter methods for its fields in the same format as the JavaBean.
Hibernate maps a domain object to a relational database in an XML file. The order and order item objects will have two mapping files to express this mapping. There are tools like Xdoclet to help with this mapping. Hibernate maps 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. Configuring Hibernate sessionfactory lets it know which database to communicate with, which data source or connection pool to use, and which persisted objects to load. The session object provided by Sessionfactory is a translation interface between Java objects and some persistence functions such as selecting, saving, updating, and deleting objects. We will discuss the Sessionfactory configuration required for Hibernate operation Session object in the later section.
Business Layer Configuration
Now that we have the domain object, we need to have a business service object that executes the application logic, executes the call to the persistence layer, obtains the request from the user interface layer, processes the transaction, and handles the exception. To connect all of these and be easy to manage, we will use the bean management aspects of the spring framework. Spring uses "control inversion" or "Setter Dependency Injection" to connect these objects, which are referenced in an external XML file. "Inversion of Control" is a simple concept that allows an object to accept other objects that are created at a higher level. Using this method, your object is freed from the need to create other objects and reduces the object coupling.
Here is an example of a subordinate object that does not use an IOC object to create it, which results in 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 the object to be created and passed to another object at a higher level, so that the other object can use the ready-made object directly [the translator note: The other objects do not have to create these objects for use in person]:
Figure 3: The object uses the IOC organization. Object A contains setter methods, which accept interfaces to Objects B and C. This can also be done with the builder that accepts objects B and C in object A.
Build our Business services audience
The setter methods we will use in our business objects accept interfaces that allow loosely defined implementations of the objects that will be set or injected. In our example, 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 convert to a different persistence framework implementation, informing spring to use the new implementation of the DAO object. You can understand how loosely coupling your business logic and your persistence mechanism to the interface and the use of "dependency injection" patterns.
Here is the interface for the business service object, which is a pile that the DAO object relies on.
Public interface IOrderService {
public abstract Order Saveneworder (order 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 preceding code has a setter method prepared for the DAO object. There is not a Getorderdao method here because it is not necessary because there is not much need to access the attached Orderdao object from the outside. The DAO object will be used to communicate with our persistent layer. We will use spring to connect the business service object with the DAO object. Because we encode to the interface, we do not tightly coupling the 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 order);
}
We have two more objects to connect with our business layers. This includes hibernatesessionfactory and a TransactionManager object. This is done directly in the spring configuration file. Spring provides a hibernatetransactionmanager that binds a hibernate session from the factory to a thread to support the transaction. Here is the spring configuration of Hibernatesessionfactory and Hibernatetransactionmanager.
Class= "Org.springframework.orm.hibernate.
Localsessionfactorybean ">
Com/meagle/bo/order.hbm.xml
Com/meagle/bo/orderlineitem.hbm.xml
Net.sf.hibernate.dialect.MySQLDialect
False
C:/mywebapps/.../web-inf/proxool.xml
Spring
class= "org.
Springframework.
Orm.
Hibernate.
Hibernatetransactionmanager ">
Each object can be referenced by a tag in the spring configuration. In this example, the Bean "Mysessionfactory" represents a Hibernatesessionfactory,bean "Mytransactionmanager" for a hibernate transaction Manager Note that the Transactionmanger bean has a property element called Sessionfactory. Hibernatetransactionmanager has a setter and getter method for Sessionfactory, which are used to inject dependency when the spring container is started. The Sessionfactory property references the Mysessionfactory bean. These two objects are now joined 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 that translate into mappingresources and hibernatepropertes prepared setter methods. Normally, 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 incorporate hibernate configuration in the spring configuration file.
Now that we have configured our container service beans and put 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:
class= "org.
Springframework.
Transaction.
Interceptor.
Transactionproxyfactorybean ">
Propagation_required,readonly,-orderexception
Propagation_required,-orderexception
Class= "com.
Meagle.
Service.
Spring.
Orderservicespringimpl ">
Class= "com.
Meagle.
Service.
Dao.
Hibernate.
Orderhibernatedao ">
Figure 4 is an overview of what we've been connected to. It shows how each object is associated and how it is set into other objects by spring. Compare this diagram to the spring configuration file in the example app 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 that we have defined. This is a useful object that knows how to handle declarative transactional operations and your service objects. You can define how transactions are handled through the Transactionattributes property, and the Transactionattributes property defines the schema for the method name and how they participate in a transaction.
The Transactionproxyfactorybean class also has a setter,target that is prepared 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 attribute, and the Orderdao bean is our DAO object that communicates with the persistent layer.
Another note about spring and beans is that beans can work in two modes. Both of these modes are defined as singleton and prototype. The default pattern for a bean is singleton, which means that an instance of a shared bean will be managed. This is used for stateless operations--like a stateless session bean will provide. When the bean is supplied by spring, the prototype mode allows a new instance of the bean to be created. You should only use prototype mode when each user needs a copy of their own bean.
Provide a service locator
Now that we have linked our services to our DAO, we need to expose our services to other tiers. This service is often used as code in the user interface layer, such as struts or swing. One simple way to do this is to use a service locator pattern class 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 of the sample app uses the Struts framework. Here we will discuss the sections related to struts when layering for an application. 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 "/>
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 fails to be saved in the persistence layer. This causes the transaction to roll back and pass the exception back to the struts layer by passing the business object. Orderminimumamountexception, a transaction in the business object logic is processed because the submitted order does not reach the minimum order quantity and the failure is also handled. The transaction will then be rolled back and the exception can be handled appropriately by the user interface layer.
The last connection step is to make our presentation layer interact with our business layer. This is done by using the service locator discussed earlier. The service layer acts as an interface to our business logic and persistence layer. This is saveneworder in struts. How the action might 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 a Order object that
Can is saved in the persistence layer.
See the full source code in the sample app.
Obtain the Wired Business service object
From the service locator configuration
In Baseaction.
Delegate the Save to the 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");
}
Conclusion
This article covers a number of topics in terms of technology and architecture. The main idea to get out of it is how to better layer your application: The user interface layer, the persistent logic layer, and any other application layer you need. This will decouple your code, allowing you to add new code components that will make your application easier to maintain in the future. The technology covered here is a good solution to this kind of problem. However, using such a framework allows you to replace the current layer with other techniques. For example, you might not want to use hibernate persistence. As 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 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 service layer. Integrating a Web application is not a trivial task, it can become easier to handle by decoupling your application layers and composing it with the appropriate framework.
Assemble web Apps with Struts+spring+hibernate