Follow my blog with Bloglovin

Friday, December 27, 2013

Spring Framework integration with Play Framework

Spring is one of the most popular Java framework, mainly known for dependency injection. Play is popular web development Java framework, but lacks dependency injection. Spring can be used for this. Integrating Spring requires following:

1. Create ApplicationContext (using Spring XML and Java config) on application start-up.

2. @Autowire fields as annotated. This will be done automatically by Spring by configuring component scan.

3. Instantiating Play controllers using Spring.

Step #0: Add Spring dependency in Play application by adding them to /project/Build.scala file:

val appDependencies = Seq(
    // Add your project dependencies here,
    javaCore,
    javaJdbc,
    javaEbean,
    "org.springframework" % "spring-context" % "3.2.6.RELEASE"
....
)

Note: If editing in Eclipse or other IDE the classpath maintained by IDE will not update with Spring dependency added. For this, run "play eclipse" (or corresponding IDE) command from Play console and then import project in IDE.
In Play 2.2.x and higher this need to be added to build.sbt in root directory of application.

Step #1: Put Spring context XMLs in /conf directory of Play application.

Sample XML with package scan:
<?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"
     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">

   <context:component-scan base-package="controllers,services,dao,config"/>


</beans>

Step #2: Add Global.java is default package in /app directory of Play application.
Global.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import constants.ApplicationConstants;

import play.Application;
import play.GlobalSettings;
import play.Play;

public class Global extends GlobalSettings{

      private ApplicationContext applicationContext;
     
      @Override
      public void onStart(Application arg0) {
            String configLocation = Play.application().configuration().getString(“spring.context.location”);
            applicationContext = new ClassPathXmlApplicationContext(configLocation);
      }
     
      @Override
      public <A> A getControllerInstance(Class<A> type) throws Exception {
            return applicationContext.getBean(type);
      }
     
}

Also, add this property in /conf/application.conf file:

# Spring configuration
spring.context.location="application-context.xml"

This is optional and can be hard coded.

Step #3: In /conf/routes file add routes configuration, prefixed with @ as :

GET / @controllers.Application.home()
GET /tracks @controllers.Application.getTrack(artist: String, genre: String, frame: String)

Also, annotate controllers.Application class with @Component Spring annotation to be scanned by Spring and add controllers package in Spring's package scan.

Sample controller class:
@Component
public class Application extends Controller {

@Autowired
private AppDAO appDAO;

public Result home(){
return ok("Hi!");
}
}

Note: 
1. No need to make controller methods static. This is helpful in mocking instances for testing.
2. Super class Controller is Play specific (play.mvc package) and annotations are Spring specific.

Annotate any class with Spring annotations like, @Component or other stereotype annotation, and @Autowire them throughout application. Beans will be created and autowired as in usual Spring application. Only controllers need spatial configuration.

Let me know if there is any issues.






Popular Posts