上一篇简单介绍了一下akka的Actor创建、消息发送接收。但都仅限于本地的消息传输。接下来尝试一下akka的远程访问的实现。
AkkaService.java
package com.yonder.akka.test.remote;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.pattern.Patterns;
import akka.util.Timeout;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
/**
* akka系统服务类
*/
public class AkkaService {
private static final Logger logger = LoggerFactory.getLogger(AkkaService.class);
private AkkaService(int port, String serverName, String actorName) {
this.host = getAddress();
this.port = port;
this.serverName = serverName;
this.actorName = actorName;
}
private ActorSystem actorSystem;
private String serverName;
private String actorName;
private String host;
private int port;
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public String getActorName() {
return actorName;
}
public void setActorName(String actorName) {
this.actorName = actorName;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
/**
* 获取akka系统服务对象
* @param port 绑定端口
* @param serverName 服务名称
* @param actorName 接收消息Actor名称
* @return
*/
public static AkkaService getInstance(int port, String serverName, String actorName){
return new AkkaService(port, serverName, actorName);
}
public void init() {
logger.info("Start ActorSystem...");
actorSystem = ActorSystem.create(serverName, createConfig());
logger.info("Start ActorSystem...OK");
ActorRef act = actorSystem.actorOf(Props.create(ReceiveActor.class), actorName);
act.tell(actorName + "已监听成功.", ActorRef.noSender());
}
private Config createConfig() {
Map map = new HashMap();
map.put("akka.loglevel", "ERROR");
map.put("akka.stdout-loglevel", "ERROR");
//开启akka远程调用
map.put("akka.actor.provider", "akka.remote.RemoteActorRefProvider");
List remoteTransports = new ArrayList();
remoteTransports.add("akka.remote.netty.tcp");
map.put("akka.remote.enabled-transports", remoteTransports);
map.put("akka.remote.netty.tcp.hostname", host);
map.put("akka.remote.netty.tcp.port", port);
map.put("akka.remote.netty.tcp.maximum-frame-size", 100 * 1024 * 1024);
//forkjoinpool默认线程数 max(min(cpu线程数 * parallelism-factor, parallelism-max), 8)
map.put("akka.actor.default-dispatcher.fork-join-executor.parallelism-factor", "50");
map.put("akka.actor.default-dispatcher.fork-join-executor.parallelism-max", "50");
logger.info("akka.remote.netty.tcp.hostname="+map.get("akka.remote.netty.tcp.hostname"));
logger.info("akka.remote.netty.tcp.port="+map.get("akka.remote.netty.tcp.port"));
return ConfigFactory.parseMap(map);
}
/**
* 获取本机ip
* @return
*/
private String getAddress() {
try {
Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces();
while (allNetInterfaces.hasMoreElements()) {
NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
continue;
}
Enumeration addresses = netInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress ip = addresses.nextElement();
if (ip != null && ip instanceof Inet4Address) {
if (ip.getHostAddress().startsWith("192") || ip.getHostAddress().startsWith("10")
|| ip.getHostAddress().startsWith("172") || ip.getHostAddress().startsWith("169")) {
return ip.getHostAddress();
}
}
}
}
return null;
} catch (SocketException e) {
logger.error("Error when getting host ip address", e.getMessage());
return null;
}
}
public void dispose() {
logger.info("Shutdown ActorSystem...");
actorSystem.shutdown();
actorSystem.awaitTermination(Duration.apply(60, TimeUnit.SECONDS));
logger.info("Shutdown ActorSystem...OK");
}
public ActorSystem getActorSystem(){
return actorSystem;
}
/**
* 访问远程Actor
* @param akkaService
* @param msg
* @return
*/
public String visitService(String serverName, String host, int port, String actorName, String msg) {
try {
ActorSelection selection = actorSystem.actorSelection(toAkkaUrl(serverName, host, port, actorName));
Timeout timeout = new Timeout(Duration.create(45, "seconds"));
Future
package com.yonder.akka.test.remote;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import akka.actor.UntypedActor;
/**
* akka消息接收类
* @author cyd
* 2016年1月11日
*
*/
public class ReceiveActor extends UntypedActor {
private static final Logger logger = LoggerFactory.getLogger(ReceiveActor.class);
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof String) {
try {
logger.info("收到消息 msg:" + msg.toString());
this.getSender().tell("Hello I'm " + this.getSelf().path().name(), getSelf());
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
this.getSender().tell("Error!", getSelf());
}
} else {
logger.info(msg.toString());
}
}
}
RemoteAkkaServer.java
package com.yonder.akka.test.remote;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 实例程序入口
* 远程服务
* @author cyd
* 2016年1月11日
*
*/
public class RemoteAkkaServer {
private static final Logger logger = LoggerFactory.getLogger(AkkaService.class);
public static void main(String[] args) {
AkkaService remoteService = AkkaService.getInstance(10002, "remoteServer", "remoteActor");
remoteService.init();
logger.info("remoteServer启动成功");
}
}
LocalAkkaServer.java
package com.yonder.akka.test.remote;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 实例程序入口
* 本地服务
* @author cyd
* 2016年1月11日
*
*/
public class LocalAkkaServer {
private static final Logger logger = LoggerFactory.getLogger(AkkaService.class);
public static void main(String[] args) {
AkkaService localService = AkkaService.getInstance(10001, "localServer", "localActor");
localService.init();
logger.info("localServer启动成功");
//由于在同一台机器上测试,所以直接取localService的ip
String str = localService.visitService("remoteServer", localService.getHost(), 10002, "remoteActor", "Hello I'm local!");
logger.info("reply:" + str);
}
}
运行结果如下
RemoteAkkaServer:
2016-01-11 14:42:36,836 [main] INFO [com.yonder.akka.test.remote.AkkaService.init:88] - Start ActorSystem...
2016-01-11 14:42:36,839 [main] INFO [com.yonder.akka.test.remote.AkkaService.createConfig:116] - akka.remote.netty.tcp.hostname=192.168.30.45
2016-01-11 14:42:36,839 [main] INFO [com.yonder.akka.test.remote.AkkaService.createConfig:117] - akka.remote.netty.tcp.port=10002
2016-01-11 14:42:37,687 [main] INFO [com.yonder.akka.test.remote.AkkaService.init:90] - Start ActorSystem...OK
2016-01-11 14:42:37,689 [main] INFO [com.yonder.akka.test.remote.AkkaService.main:20] - remoteServer启动成功
2016-01-11 14:42:37,689 [remoteServer-akka.actor.default-dispatcher-3] INFO [com.yonder.akka.test.remote.ReceiveActor.onReceive:22] - 收到消息 msg:remoteActor已监听成功.
2016-01-11 14:42:44,355 [remoteServer-akka.actor.default-dispatcher-4] INFO [com.yonder.akka.test.remote.ReceiveActor.onReceive:22] - 收到消息 msg:Hello I'm local!
LocalAkkaServer:
2016-01-11 14:42:43,330 [main] INFO [com.yonder.akka.test.remote.AkkaService.init:88] - Start ActorSystem...
2016-01-11 14:42:43,333 [main] INFO [com.yonder.akka.test.remote.AkkaService.createConfig:116] - akka.remote.netty.tcp.hostname=192.168.30.45
2016-01-11 14:42:43,333 [main] INFO [com.yonder.akka.test.remote.AkkaService.createConfig:117] - akka.remote.netty.tcp.port=10001
2016-01-11 14:42:44,180 [main] INFO [com.yonder.akka.test.remote.AkkaService.init:90] - Start ActorSystem...OK
2016-01-11 14:42:44,182 [main] INFO [com.yonder.akka.test.remote.AkkaService.main:21] - localServer启动成功
2016-01-11 14:42:44,182 [localServer-akka.actor.default-dispatcher-3] INFO [com.yonder.akka.test.remote.ReceiveActor.onReceive:22] - 收到消息 msg:localActor已监听成功.
2016-01-11 14:42:44,373 [main] INFO [com.yonder.akka.test.remote.AkkaService.main:24] - reply:Hello I'm remoteActor
实例中远程Actor传输的是字符串,远程Actor还可以传输对象,这让一些业务逻辑的实现变得更为简单方便。
akka的并发编后续再进行探讨