Spring은 종합선물세트라 이런게 다 잘 되어 있지만 play framework는 사실 개념도 좀 다르고 해서 기본으로 탑재되어 있지는 않은 듯. 그래서 google에서 plug-in을 만들어 줬다.
설정은 간단하다. build.sbt 혹은 Build.scala(2.2 이하)에 dependency만 추가해 주면 사용이 가능하다. 현재 3.0까지 있고 3.0이 릴리즈된지 꽤 된 것 같아서 beta지만 4.0을 써보기로 한다.
libraryDependencies ++= Seq( "org.mybatis" % "mybatis" % "3.1.1", "mysql" % "mysql-connector-java" % "5.1.26", "net.sf.flexjson" % "flexjson" % "3.1", "com.google.inject" % "guice" % "4.0-beta", javaCore, javaJdbc, cache )
목표는 DI의 의미에 맞게 컨트롤러에 다 모여 있던 서비스에 해당하는 부분을 분리하고 그 서비스는 다시 인터페이스와 그 구현부로 나눈 후에 그걸 컨트롤러에 주입(Injection)하는 것이므로 우선 서비스를 제조한다. 인터페이스부터 시작.
패키지는 알아서 만들고 인터페이스는 아래와 비슷하게 만든다.
package services; import models.User; public interface UsersService { public User getUser(String id); }
이제 저 인터페이스의 구현체를 만든다. UsersDAO는 신경쓰지 말고 일단 구현.
package services.impl; import dao.UsersDAO; import models.User; import services.UsersService; public class UsersImpl implements UsersService { private UsersDAO userDao; public UsersImpl() { play.Logger.info("Users services constructor"); } @Override public User getUser(String id) { userDao = new UsersDAO(); User user = userDao.getUser(id); return user; } }
구현체까지 만들었으면 이제 컨트롤러로 이동한다.
package controllers; import com.google.inject.Inject; import models.User; import flexjson.JSONSerializer; import play.mvc.Controller; import play.mvc.Result; import services.UsersService; public class UsersController extends Controller { @Inject private UsersService usersService; public Result getUser(String id) { JSONSerializer serializer = new JSONSerializer(); User user = new User(); user = usersService.getUser(id); String jsonResult = serializer.prettyPrint(true).serialize(user); play.Logger.info(jsonResult); return ok(jsonResult); } }
저기서 @Inject 어노테이션으로 서비스를 컨트롤러에 주입하는 부분이 핵심이다. 그리고 실제 usersService를 사용하는 부분이 있는데 이 다음에 만들 GlobalSetting이 어설프면 저게 안된다. 주입이 안되니 객체도 없으니까.
그럼 이제 후반부 작업. routes를 손봐야 한다. 보다시피 컨트롤러의 메소드가 기존과 달리 static이 아닌데 routes의 url에 매핑된 메소드가 더 이상 static이 아니므로 @ 심볼을 붙여줘야 한다. 그래야 알아먹음.
GET /users/:id @controllers.UsersController.getUser(id: String)
이제 마지막. app/Global.java로 injection setting 클래스를 만들어 준다. 파일의 위치에 주의할 것. 분리한답시고 다른 폴더 만들어서 거기 넣어두면 읽지를 못해서 위의 컨트롤러에 주입해 준 서비스를 불러오지 못한다. 그래서 NullpointerException이 발생함.
Injector를 만들고 injector에서 객체를 반환받기 위해 getControllerInstance메소드를 오버라이드 한다. 위의 @ 심볼이 붙은 url로 접근하면 이 메소드를 호출한단다.
import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import play.Application; import play.GlobalSettings; import services.UsersService; import services.impl.UsersImpl; public class Global extends GlobalSettings { private Injector injector; @Override public void onStart(Application application) { injector = Guice.createInjector(new AbstractModule() { @Override protected void configure() { bind(UsersService.class).to(UsersImpl.class); } }); } @Override public <t> T getControllerInstance(Class<t> aClass) throws Exception { return injector.getInstance(aClass); } }
이제 다시 테스트를 해 보면 기존과 같이 잘 되는 것을 볼 수 있음.
댓글 없음:
댓글 쓰기