Using Spring as a dependency injection framework with play 2.4.x?

I am exploring play-scala 2.4.2 and trying to get the spring DI working with it. I see there are a lot of changes in play 2.4.x and old way of overriding the GlobalSettings.getControllerInstance seems to be no more an option.

I came across this project https://github.com/jroper/play-spring, but it seems to be more of a POC proving that Spring DI is possible but does not seems to be as easy as in earlier play versions. Will this be the spring integration mechanism for current and future play versions or a simpler mechanism or framework can be expected sometime soon from the play community?


Please follow the following steps:

Step1: Add the spring dependencies in build.sbt file.

libraryDependencies += "org.springframework" % "spring-context" % "4.1.6.RELEASE"
libraryDependencies += "org.springframework" % "spring-core" % "4.1.6.RELEASE"
libraryDependencies += "org.springframework" % "spring-beans" % "4.1.6.RELEASE"
libraryDependencies += "org.springframework" % "spring-aop" % "4.1.6.RELEASE"

Step2: Create a new class ( ApplicationGlobalSettings.java ) and that implements with GlobalSettings class.

package com.ranga.global.settings;

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

import play.Application;
import play.GlobalSettings;
public class ApplicationGlobalSettings extends GlobalSettings { 


private static final String APPLICATION_CONTEXT_XML = "applicationContext.xml";
private ConfigurableApplicationContext applicationContext;

@Override
public void beforeStart(Application application) {      
    super.beforeStart(application);
}

@Override
public void onStart(Application application) {      
    super.onStart(application);     
    applicationContext = new ClassPathXmlApplicationContext(APPLICATION_CONTEXT_XML);           
}

@Override
public void onStop(Application application) {       
    super.onStop(application);
    if(applicationContext != null) {
        applicationContext.close();
    }
}

}

Step3: Create a new spring configuration file under conf folder ( applicationContext.xml ) confapplicationContext.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"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   <context:component-scan base-package="com.ranga.services, com.ranga.daos"/>

</beans>

Step4: Add the newly created GlobalSettings file location to the application configuration file ( conf/application.conf ).

.....some more configuration here.....
# Global Objects class
application.global=com.ranga.global.settings.ApplicationGlobalSettings

Step5: Create a new service class under com.ranga.service package (HelloWorldService.java).

package com.ranga.services;
import javax.inject.Inject;
import org.springframework.stereotype.Service;

import com.ranga.daos.HelloWorldDAO;
@Service
public class HelloWorldService {

    @Inject
    private HelloWorldDAO helloWorldDAO;

    public String sayHello() {
        return helloWorldDAO.sayHello();
    }
}

Step6: Create a new dao class under com.ranga.daos package ( HelloWorldDAO.java ).

package com.ranga.daos;

import org.springframework.stereotype.Repository;
@Repository
public class HelloWorldDAO {
    public String sayHello() {
        return "Hello Ranga!";
    }
}

Step7: Finally inject the HelloWorldService in Application.java file.

package com.ranga.controllers;

import javax.inject.Inject;

import org.springframework.beans.factory.annotation.Autowired;

import com.ranga.services.HelloWorldService;

import play.*;
import play.mvc.*;

import views.html.*;

public class Application extends Controller {

    @Inject
    private HelloWorldService helloWorldService;

    public Result index() {         
        return ok(index.render(helloWorldService.sayHello()));
    }
}

Step8: Finally modify the index.scala.html file code.

@(message: String)

<h1>@message</h1>

Now done.. run the application.


The latest version of Play:

Create the class Global (Old Global than extended GlobaSettings):

@Singleton
public class Global {

    private static final String APPLICATION_CONTEXT = "applicationContext.xml";

    private ConfigurableApplicationContext applicationContext;

    @Inject
    public Global( ApplicationLifecycle lifecycle ) {
        applicationContext = new ClassPathXmlApplicationContext(APPLICATION_CONTEXT_XML);
        lifecycle.addStopHook( () -> {
            applicationContext.close();
            return F.Promise.pure( null );
        });
    }

}

Create the class ConfigurableApplicationContextModule:

public class ApplicationContextModule extends AbstractModule {

    @Override
    protected void configure() {
        bind( Global.class ).asEagerSingleton();
    }

}

In application.conf add this:

play.modules.enabled += "config.ApplicationContextModule"

Create file applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

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

</beans>

After creating what stated above by Ranga


Just in case it can help someone, I also worked on a solution that is working based off of jroper's project: https://github.com/jroper/play-spring. The key was to use spring's scanning feature to "load" the Play classes:

ctx.scan(packages:_*)

with the default play's packages:

def defaultPackages(): Seq[String] = Seq("router", "play", "controllers")

The solution works with 1 hack: you need to add the @javax.inject.Named next to the @Singleton annotations in the Play classes so that Spring can scan them and load them (ie you need to "fork" the Play version you are using, but it's a rather small and easy change). So here is my sample app with the SpringApplicationLoader: https://github.com/remithieblin/play24_spring

链接地址: http://www.djcxy.com/p/27486.html

上一篇: 在LZ77 / LZSS上与后缀树匹配重叠前瞻

下一篇: 使用Spring作为2.4.x的依赖注入框架?