Sunday, February 12, 2012

Spring 3.0 Framework - Spring XML Configuration of a Spring MVC Application

Disclaimer:
All the software applications that appear below represent trademarks and they are the property of their respective owners.
Use and implement my notes in this article at your own risk.

The following topics are discussed:
1. Goals of Spring XML Configuration;
2. Overview of Spring XML Configuration;
3. Sample of app-config;
4. Sample of a Spring business service.
5. Sample of mvc-config.xml;
6. Sample of a Spring controller.
7. Considerations


(view of app in action)

1. Goals of Spring XML Configuration
The main goal of Spring XML Configuration is to have all the Spring components configured by using xml files.
This means that there will not be present any other type of Spring Configuration (like annotations or configuration via Java classes).
However, the Hibernate entities will be configured to use annotations, as it is probably the best practice to keep under observation the Hibernate Configuration under a Spring MVC application.

2. Overview of Spring XML Configuration
A Spring XML Configuration uses Spring namespaces to make available the sets of XML tags used in the configuration; the main Spring namespaces are: context, beans, jdbc, tx, aop, mvc, aso.
As we said at the General Considerations, a Spring configuration is splitted in 2 sections:
a. app-config.xml file that configures the business components that is loaded by the Spring ContextLoaderListener;
In app-config we will have:
- a bean xml tag to define the datasource to bind to the MySQL database; we'll specify here: the JDBC driver for MySQL, the url of MySQL server, MySQL server username and passowrd;
- a bean xml tag to define the session factory that will create Hibernate sessions; we'll specify here: the datasource defined above, as a Hibernate session uses a database connecton; then, we will tell Hibernate which are the classes that maps the database tables; then we'll tell Hibernate what behaviour to have taking into account we use a MySQL database;
- a tx xml tag that will create the transaction manager; we'll specify here the session factory used to create Hibernate sessions that will be transacted;
- an aop xml tag used to specify which are the business methods that will be transacted and how they will be transacted;
- a bean xml tag (namely PersistenceExceptionTranslationPostProcessor) that will tell Spring to pass Hibernate type exceptions to Spring type exceptions;
- an xml bean tag for each of the Spring services used to manipulate data on Hibernate entities; we'll specify here the session factory that will be injected in the respective Spring service;
b. mvc-config.xml file that configures the Controllers and Views Rendering that is loaded by Spring DispatcherServlet;
In mvc-config we'll have:
- a mvc xml object that will define the list of Spring interceptors; in this list we'll define a bean xml tag, namely OpenSessionInViewInterceptor, that we'll lazily open the Hibernate sessions in order to be processed by Spring services;
- a bean xml tag for each of the Spring controllers used to forward, retrieve and define the finally HTML rendered views; we'll specify here the Spring services that will be injected in the controller in order to get and set the data in the database;
- a bean xml tag to define the view resolver that will set the type of the view;

Note: both XML configuration files can extend other XML configuration files by importing them. For example we may have a file that defines the datasource, then another file that defines the session factory, then another file that defines the Spring services, then all 3 may be included in a single app-config.xml file.
Note: app-config.xml and mvc-config can have any other names, as long as they are specified in web.xml at their respective "contextConfigLocation" values.

3. Sample of app-config;
<<
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                            http://www.springframework.org/schema/jdbc
                            http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
                            http://www.springframework.org/schema/tx
                            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/blog" />
        <property name="username" value="root" />
        <property name="password" value="" />
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>blog.dao.entities.Zone</value>
                <value>blog.dao.entities.Country</value>
                <value>blog.dao.entities.City</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.max_fetch_depth">3</prop>
                <prop key="hibernate.show_sql">false</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
       
    <tx:advice id="txAdviceTransactionManager" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
            <tx:method name="*" read-only="true" propagation="SUPPORTS" isolation="DEFAULT" rollback-for="org.springframework.dao.DataAccessException" />           
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="transactionalOperation"
            expression="execution(* blog.services.*Impl.*(..))" />
        <aop:advisor advice-ref="txAdviceTransactionManager"
            pointcut-ref="transactionalOperation" />
    </aop:config>
   
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

    <bean id="zoneDao" class="blog.services.ZoneDaoImpl">
        <constructor-arg ref="sessionFactory" />
    </bean>

    <bean id="countryDao" class="blog.services.CountryDaoImpl">
        <constructor-arg ref="sessionFactory" />
    </bean>

    <bean id="cityDao" class="blog.services.CityDaoImpl">
        <constructor-arg ref="sessionFactory" />
    </bean>
 </beans>

 >>

4. Sample of a Spring business service.

We will pass here the Java code used to create the Zone Spring service (namely ZoneDaoImpl), as an implementation of a user created ineterface (namely ZoneDao):
<<
package blog.services;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import blog.dao.ZoneDao;
import blog.dao.entities.Zone;

public class ZoneDaoImpl implements ZoneDao {

    private SessionFactory sessionFactory;

    public ZoneDaoImpl(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @SuppressWarnings("unchecked")
    public List<Zone> getZones() {
        return (List<Zone>) getCurrentSession().createQuery("from Zone").list();
    }

    public Zone getZoneByCod(String cod) {
        return (Zone) getCurrentSession().createQuery("from Zone z where z.cod=?").setParameter(0, (String) cod).uniqueResult();
    }

    public Zone getZoneByName(String name) {
        return (Zone) getCurrentSession().createQuery("from Zone z where z.name=?").setParameter(0, (String) name).uniqueResult();
    }

    protected Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }
}

>>


5. Sample of mvc-config.xml;
<<
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                        http://www.springframework.org/schema/mvc     http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <mvc:interceptors>
        <bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    </mvc:interceptors>
   
    <bean name="/zoneList" class="blog.controllers.ZoneController">
        <constructor-arg ref="zoneDao"/>
    </bean>

    <bean name="/countryList" class="blog.controllers.CountryController">
        <constructor-arg ref="countryDao"/>
    </bean>

    <bean name="/cityList" class="blog.controllers.CityController">
        <constructor-arg ref="cityDao"/>
    </bean>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
   
</beans>

>>

6. Sample of a Spring controller.

We will pass here the code used to create the Zone controller (namely ZoneController):
<<
package blog.controllers;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import blog.dao.ZoneDao;

public class ZoneController {
   
    private ZoneDao zoneDao;
   
    public ZoneController(ZoneDao zoneDao) {
        this.zoneDao = zoneDao;
    }
   
    @RequestMapping("/zoneList")
    public String zoneList(Model model) {
        model.addAttribute("zones", zoneDao.getZones());
        return "zoneList";
    }

}

>>

7. Considerations
The Spring XML Configuration may be useful as:
- we have all the Spring components configuration in only 2 files: app-config.xml and mvc-config.xml;
- XML files are text files, so they may be updated in a Java archive like a WAR for example;

However, the Spring XML Configuration is not well received by the users that like the programatic way of designing web applications or by those users that will say "ohhh, and do I have to write all this XML code ?!".
For these users, there were defined the next 2 kind of Spring MVC Configuration, namely the annotation and JavaConfig.

No comments:

Post a Comment