Spring Framework + Akka Actor + Maven 사용하기

Spring Framework + Akka Actor + Maven 사용하기

개발 중에 요청에 대한 로그를 남기는 부분이 있는데 로거를 사용하기에 부족한 부분이 있고 async로 처리해야 하는 부분이 생겨 akka actor를 사용하여 구현하게 되었다.

akka.io 사이트의 메뉴얼을 확인해보면.. Spring 연계 개발을 1.3.1까지만 지원하고 있고 다음 버전인 2.0.5에서는 아직 마이그레이션이 안되었다는 메세지가 나와 있다.

이번 포스트에서는 akka 1.3.1 버전으로 Spring 과 연계하는 방법을 정리해보려고 한다. akka actor에서 Spring bean을 DI 하고, 반대로 Spring bean에서 akka actor(정확히는 actorRef)를 받아와서 메세지를 전달하는 과정을 구현해보도록 한다.

우선 pom.xml 파일에 두개의 dependency를 추가해야 한다. akka 라이브러리만 추가해 놓고 한참 삽질을 했다. akka-spring 라이브러리에서 의존성을 갖고있는 spring-beans, spring-context는 프로젝트에서 사용하는 버젼과 다를 수 있으므로 제외(exclusion)시켜 주도록 한다.

pom.xml <dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
      <!-- akka-actor -->
        <dependency>
            <groupId>se.scalablesolutions.akka</groupId>
            <artifactId>akka-actor</artifactId>
            <version>1.3.1</version>
        </dependency>
      <!-- akka-spring -->
        <dependency>
            <groupId>se.scalablesolutions.akka</groupId>
            <artifactId>akka-spring</artifactId>
            <version>1.3.1</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

다음으로 akka actor를 생성해주도록 한다.

MyActor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package actor;
import akka.actor.UntypedActor;
import service.interface.PlanService;
public class MyActor extends UntypedActor {
  private PlanService planService;
    @Override
    public void onReceive(Object message) throws Exception {
        if (message.equals("PlanA")) {
          planService.doA();
        } else if (message.equals("PlanB")) {
          planService.doB();
        }
    }
}

context xml 파일에 akka actor를 Bean으로 등록해준다. 주의할 점은 사용하고 싶은 bean을 property로 선언하여 주입 받아야 한다. (Autowired 어노테이션이 제대로 동작하지 않는 것 확인)

context.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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:akka="http://akka.io/schema/akka"
       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
                        http://akka.io/schema/akka http://akka.io/akka-1.3.1.xsd">
  <!-- 생략 -->
    <akka:untyped-actor id="myActor"
                        implementation="actor.MyActor"
                        scope="singleton"
                        autostart="true">
      <property name="planService" ref="planService"/>
    </akka:untyped-actor>
</beans>

Spring bean에서 actor를 사용하는 부분을 구현해보자. 여기도 마찬가지로 @Autowired가 정상적으로 동작하지 않는 것으로 확인되어 @PostConstruct method에서 getBean해서 사용하는 방식으로 구현하도록 한다.

MyServiceImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
class MyServiceImpl implements MyService{
    private ActorRef myActor;
    @PostConstruct
    public void init() {
        myActor = (ActorRef) context.getBean("myActor");
    }
  @Override
  public void doService(String plan) {
      myActor.tell(plan);
  }
}

이와 같이 Actor, Spring bean간 서로 주입을 받을 수 있다. 서비스 중 시간이 오래걸리지만 async로 처리할 수 있는 부분이 있다면 actor로 분리하여 처리하는 것도 하나의 방법일 수 있다.