Sunday, February 12, 2012

Spring 3.1 Framework - Spring 3.1 Java 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 JavaConfig;
2. Spring Librairies Update
3. Overview of Spring JavaConfig;
4. Sample of AppConfig.java;
5. Sample of a Spring business service.
6. Sample of MvcConfig.java;
7. Sample of a Spring controller.
8. Considerations


(view of Spring app in action)

1. Goals of Spring JavaConfig
The main goal of Spring JavaConfig is to eliminate the XML code used to configure all the Spring components and to keep all the configuration in 2 main JavaConfig classes, namely, for example, AppConfig.java and MvcConfig.java.
This means practically passing all the configuration from XML to Java classes.

Note: this post is based on the previous one, namely "Spring 3.0 Java Configuration" which you should read before this one; next, we'll try to show that almost all the JavaConfig problems found at Spring 3.0 were solved at Spring Framework 3.1 release.

2. Spring Librairies Update
If you followed the Genereal Considerations, at the section "4. Assembly librairies" we used some Spring Framework 3.0.5 libraries. Now, these libs should be replaced with Spring Framework 3.1.0 libs.

So, in your app classpath, replace these libs:
<<
spring-aop-3.0.5.RELEASE.jar
spring-asm-3.0.5.RELEASE.jar
spring-beans-3.0.5.RELEASE.jar
spring-context-3.0.5.RELEASE.jar
spring-core-3.0.5.RELEASE.jar
spring-expression-3.0.5.RELEASE.jar
spring-javaconfig-1.0.0.m3.jar
spring-jdbc-3.0.5.RELEASE.jar
spring-orm-3.0.5.RELEASE.jar
spring-tx-3.0.5.RELEASE.jar
spring-web-3.0.5.RELEASE.jar
spring-webmvc-3.0.5.RELEASE.jar

>>
, with these ones:
<<
org.springframework.asm-3.1.0.RELEASE.jar
org.springframework.beans-3.1.0.RELEASE.jar
org.springframework.context-3.1.0.RELEASE
org.springframework.core-3.1.0.RELEASE.jar
org.springframework.expression-3.1.0.RELE
org.springframework.jdbc-3.1.0.RELEASE.jar
org.springframework.orm-3.1.0.RELEASE.jar
org.springframework.transaction-3.1.0.RELEASE.jar
org.springframework.web-3.1.0.RELEASE.jar
org.springframework.web.servlet-3.1.0.RELEASE.jar

>>

3. Overview of Spring JavaConfig

As we said before at Spring 3.0 JavaConfig, there are used special annotations in JavaConfig: @Configuration, @Import, @ImportResource, @Bean, aso.
For the Spring 3.1 JavaConfig, we'll use another annotations: @ComponentScan and @EnableTransactionManagement.
The @ComponentScan annotation intends to solve the problems of scanning packages for Spring components, in order for us not to define them in AppConfig.java and MvcConfig.java.
The @EnableTransactionManagement annotation will tell Spring to use driven annotated transactions or, more exactly, to detect the @Transactional annotation that we mapped in a Spring business component; The @EnableTransactionManagement annotation is equivalent to XML tag declaration: <tx:annotation-driven />, so after we use @EnableTransactionManagement we'll not need anymore the app-config.xml file that was imported in AppConfig.java (see Spring 3.0 JavaConfig).



4. Sample of AppConfig.java;
<<
package blog.configuration;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@ComponentScan("blog.services")
@EnableTransactionManagement

public class AppConfig {
   
    @Bean(name="dataSource")
    public DataSource dataSource() {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUsername("root");
        ds.setPassword("");
        ds.setUrl("jdbc:mysql://127.0.0.1:3306/blog");
        return ds;
    }

    @Bean(name="sessionFactory")
    public SessionFactory sessionFactory() {
        AnnotationSessionFactoryBean factoryBean = null;
        try {
            factoryBean = new AnnotationSessionFactoryBean();
            Properties pp = new Properties();
            pp.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
            pp.setProperty("hibernate.max_fetch_depth", "3");
            pp.setProperty("hibernate.show_sql", "false");
   
            factoryBean.setDataSource(dataSource());
            factoryBean.setPackagesToScan(new String[] {"blog.dao.*"});
            factoryBean.setHibernateProperties(pp);
            factoryBean.afterPropertiesSet();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factoryBean.getObject();
    }
   
    @Bean(name="transactionManager")
    public HibernateTransactionManager transactionManager() {
        return new HibernateTransactionManager(sessionFactory());
    }
   
}

>>

Note: we observe in this file all the Java bean objects (Spring business components) that we defined in AppConfig.java at Spring 3.0 JavaConfig dissapeared. Also notice the presence of @ComponentScan and @EnableTransactionManagement annotations.

5. 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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class ZoneDaoImpl implements ZoneDao {

    private SessionFactory sessionFactory;

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

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

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

    @Transactional(readOnly = true)
    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();
    }
}

>>
Note: as we used @ComponentScan in AppConfig.java, we need to use the @Service and @Autowired in ZoneDao Spring service.

6. Sample of MvcConfig.java;
<<
package blog.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@ComponentScan("blog.controllers")

public class MvcConfig {

    @Bean
    InternalResourceViewResolver irResolver() {
        InternalResourceViewResolver ir = new InternalResourceViewResolver();
        ir.setPrefix("/views/");
        ir.setSuffix(".jsp");
        return ir;
    }

}

>>

Note: we observe in this file all the Java bean objects (Spring controllers) that we defined in MvcConfig.java at Spring 3.0 JavaConfig dissapeared. Also notice the presence of @ComponentScan.
Note: Because we replaced OpenSessionInViewInterceptor with OpenSessionInViewFilter and moved it in web.xml, we do not need anymore the mvc-config.xml file.

7. 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import blog.dao.ZoneDao;

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

}

>>
Note: as we used @ComponentScan in MvcConfig.java, we need to use the @Controller and @Autowired in ZoneController.

8. Considerations
The Spring JavaConfig may be useful as:
- we may keep all the configuration in 2 Java classes;
- no XML code for XML haters;

However, when used Spring 3.1 JavaConfig, I still haven't found a way to map the OpenSessionInViewInterceptor at the level of MvcConfig.java; a starting point could be to inherit the WebMvcConfigurerAdapter class in MvcConfig.java and to override the addInterceptors() method

6 comments:

  1. Hi, which one is best way to develop application whether xml based configuration or java based configuration... please describe me in detail... thanks

    ReplyDelete
  2. Hi Kavi, as you seen there are 3 ways to configure Spring; each one has its advantages and disadvantages; much more, the "JavaConfig" is still in development and if you choose this one, you better use the Spring 3.1 libs; "JavaConfig" announces to be the best Spring config, but, due to development issues, I will choose between the others 2: xml and annotations; you will find my personal considerations at the "Considerations" section on each config article; also, you should choose the proper config based on your project specifics.

    ReplyDelete
  3. hello, can you please send the sample at hukd.deals@gmail.com??

    ReplyDelete
  4. Regarding your last comment. To set the OpenSessionInViewInterceptor using Java Config you go:

    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {

    @Autowired
    SessionFactory sessionFactory;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    OpenSessionInViewInterceptor osiv = new OpenSessionInViewInterceptor();
    osiv.setSessionFactory(sessionFactory);
    registry.addWebRequestInterceptor(osiv);
    }

    }

    ReplyDelete
  5. @Jason: thank you for the comment - it really is a good asset for the community :)

    ReplyDelete
  6. Hi all,
    I know there were guys that wanted the code and probably I couldn't send them the code in useful time. First of all I want to apologize to all these guys.
    Second, due to latest activity, I really have no time to maintain this blog, so I want you guys understand I CANNOT SEND THE CODE ANYMORE.
    In this case, you have 2 solutions:
    1) the main aspects for each sample are already posted on respective topics; practically, if you read the "general considerations" and the related topics, you will not need the code; you just need to configure a new app and paste there the code from the topics;
    2) if you really want the code, then ALL THE GUYS THAT PUT THEIR EMAILS ON THE COMMENTS ABOVE HAVE RECEIVED THE CODE; so, if I cannot respond, then maybe they can ;) in fact, it is a distributable code, isn't it ? ;)
    I hope you guys understand the above, thanx, vsorinel.

    ReplyDelete