akka 2.5.16远程访问Actor

 

         今天搞了一下远程访问actor,顺便写个笔记记录一下过程。

废话少说,直接干代码:

     建立服务端

      第一步:构建项目结构。使用maven管理jar包(说实话,maven实在是太好使了,爱不释手),简单粗暴一点直接从akka官网自动生成一个基于java的maven项目,里面有完整的项目结构。其中build.sbt,sbt,sbt.bat, build.sbt这些乱七八糟的可以不用理他,对了在这里要注意jdk的版本问题,一定要在jdk8以上,但是本人当时使用了一个jdk1.8.0_20的版本,报了一堆乱七八糟的数字码,字符码错误。最后换了个jdk1.8.0_121的就可以了,真实有点坑,网上好多说用jdk8以上的版本就可以(难道我用了一个假的jdk8,哈哈),将项目导入到eclipse或者idea中,我使用的是idea,然后删除项目里的自带的java文件和测试的java文件。开始编写自己的代码。

   第二歩:在项目的包下,新建一个消息对象SetRequest,记住要实现Serializable接口哦,否则可是无法再网络上传输的。

package com.lightbend.akka.sample;

import java.io.Serializable;

public class SetRequest implements Serializable {
    public final String key ;
    public final String value ;
    public SetRequest(String key ,String value) {
        this.key = key;
        this.value = value;
    }

}

 第二歩:新建一个Actor,这可是akka的一个重要的家庭成员。

package com.lightbend.akka.sample;

import akka.actor.AbstractActor;
import akka.actor.Actor;
import akka.actor.ActorRef;
import akka.actor.Status;
import akka.japi.pf.FI;

import java.util.HashMap;
import java.util.Map;

public class SetRequestActor extends AbstractActor {
    public final Map map = new HashMap();
    @Override
    public Receive createReceive() {
        Receive receive = receiveBuilder().match(SetRequest.class, setRequest -> {
            map.put(setRequest.key,setRequest.value);
            //客户端那边的actor,这是一个临时的actor,被akka自动创建的
            ActorRef actorRef = sender();  

            System.out.println("actorRef : " + actorRef);
            /**
              * 向发送请求的actor发送响应信息,actorRef是要接受响应信息的对象,tell第一个参数
              * 是响应给客户端的信息,第二个参数是谁响应给actorRef的,在这里并没有告诉是谁响应的
              * 下面其它类型的消息都可以这么理解。
              */
            actorRef.tell("save success",ActorRef.noSender());
        }).match(String.class, str ->{
            System.out.println("receive string : " + str);
            sender().tell("receive success", Actor.noSender());
        }).matchAny(request -> {
            ActorRef actorRef = sender();
            actorRef.tell(new Status.Failure(new Exception("不知道是什么类型的信息")),ActorRef.noSender());
        }).build();
        return receive;
    }
}

 第三歩:添加远程支持。在这一步,我们干一些小事情,但不可小视,在pom.xml中引入远程依赖包。如果没有这个依赖,那就放弃吧。。。。。。。。。。。。。。。。。。。尽量版本要保持一致(讲真,版本真是一个让人蛋疼的东西)。


    com.typesafe.akka
    akka-remote_2.12
    2.5.16

依赖完成之后,难道就行了吗,不可能的。我们还要创建远程配置文件。这个看书上的,虽然就这几行,能耐可不小。该文件的位置在src/main/resources文件夹下。这个文件不同介绍了吧,一看就明白。(不过在这里先给个warn,注意一下端口,因为端口让我踩了一个大坑,到文章末尾的时候,我会介绍一下)。

akka {
    actor {
        provider = "akka.remote.RemoteActorRefProvider"
    }
    remote {
        enabled-transports = ["akka.remote.netty.tcp"]
        netty.tcp {
            hostname = "127.0.0.1"
            port = 2552
        }
    }
}

第四步: 开始我们表演的时候,启动该服务,创建启动类(就是个main方法!!!!!!!).

package com.lightbend.akka.sample;

import akka.actor.ActorSystem;
import akka.actor.Props;

public class BootAkka {
    public static void main(String[] args) {
        System.out.println("server start.......");
        //创建服务端的actor系统,名字随便起
        ActorSystem actorSystem = ActorSystem.create("akkademy");
        //注册actor对象,并给actor起个名字,这里叫remoteActor,其它名字也可以,但在客户端访问的时候要和这里起的名字保持一致,否则数据时传输不过来的。
        actorSystem.actorOf(Props.create(SetRequestActor.class),"remoteActor");
    }
}

 第五步:okay,让我们开始运行服务端吧。激动人心的时候到了。

server start.......
[INFO] [09/16/2018 19:36:28.425] [main] [akka.remote.Remoting] Starting remoting
[INFO] [09/16/2018 19:36:29.262] [main] [akka.remote.Remoting] Remoting started; listening on addresses :[akka.tcp://[email protected]:2552]
[INFO] [09/16/2018 19:36:29.265] [main] [akka.remote.Remoting] Remoting now listens on addresses: [akka.tcp://[email protected]:2552]

看到了吧,好使, 没毛病!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

构建客户端:

服务端完事了之后,那就开始我们的客户端吧,没有用户的应用有个毛用。那么还是照旧,采取分步走战略,我就喜欢步骤清晰的(最讨厌这写一句,那讲一句,看的宝宝都没心情了,哈哈)介绍。

第一步:第一步干啥那?你猜,当然建工程了(正经的:我所使用的是服务端使用一个项目,客户端再建一个项目,能够从直观上产生远程的感觉,当然也可以在一个工程下做远程访问actor,所以我就采用使用新建了两个项目)。新建一个客户端对象类。

package com.lightbend.akka.sample.service;

import akka.actor.*;
import com.lightbend.akka.sample.GetRequest;
import com.lightbend.akka.sample.SetRequest;

import javax.annotation.processing.Completion;
import java.util.concurrent.CompletionStage;

import static akka.actor.TypedActor.self;
import static akka.pattern.Patterns.ask;
import static scala.compat.java8.FutureConverters.toJava;

public class JClient {
   
    private  final ActorSystem system = ActorSystem.create("LocalSystem");  //客户端actor系统,名字随便起
  
    private final ActorSelection  remoteDb;  // 远程actor对象。

    private ActorRef actorRef = null ;

    public JClient(String remoteAddress) {
        //通过远程actor地址,找到远程actor对象
        remoteDb = system.actorSelection("akka.tcp://akkademy@" + remoteAddress + "/user/remoteActor");

        if (remoteDb != null) {  //做日志输出信息,并没有太大的用途,读者可以跳过这一个行代码
            System.out.println("remoteDb ==null :" + remoteDb.path().mkString());
        }
    }

    public CompletionStage set(String key, String value) {
        //向远程actor发送请求,使用ask方法,第一个参数是远程actor对象引用,第二个参数是要发送的消息对象,第三个是超市的毫秒数,如果在2秒内未响应则按超时处理。

        return toJava(ask(remoteDb,new SetRequest(key,value),2000));
    }
 

}

 第二歩:开启远程访问。引入远程访问的依赖,怎么引不用说了吧,和服务端一样,远程依赖引入之后,还要创建远程配置文件,注意一下端口,和上面的不一样,如果和上面的一样,那么在启动服务器之后,再启动客户端,此时会报端口被占用异常,也就是说ActorSystem不能运行在同一个服务器的同一个端口上,这个是一定要切记的,这也是在构建服务端时,我说的注意的端口的问题,这个端口被占用的问题搞了我一下午,就是不知道为什么端口异常,最后更改了客户端的port之后,一切就正常了。

akka {
    actor {
        provider = "akka.remote.RemoteActorRefProvider"
    }
    remote {
        enabled-transports = ["akka.remote.netty.tcp"]
        netty.tcp {
            hostname = "127.0.0.1"
            port = 2550
        }
    }
}

第三歩:开启启动客户端。 

package com.lightbend.akka.sample.service;

import com.lightbend.akka.sample.GetRequest;
import com.lightbend.akka.sample.KeyNotFoundMsg;

import java.util.concurrent.CompletionStage;

import static akka.pattern.Patterns.ask;

public class ClientMain {
    public static void main(String[] args) {
        JClient jClient = new JClient("127.0.0.1:2552");
        CompletionStage completionStage = jClient.set("age","12");
        completionStage.thenAccept(response ->{
            System.out.println("response :" + response);
        });
    }
}

怎么样简单吧, 看着根本没什么压力,之前看别人写的例子,本来问题就不大,结果一个java文件就写了一大坨,宝宝流泪了。

还等什么,那就开始运行喽。


[INFO] [09/16/2018 20:05:02.286] [main] [akka.remote.Remoting] Starting remoting
[INFO] [09/16/2018 20:05:03.058] [main] [akka.remote.Remoting] Remoting started; listening on addresses :[akka.tcp://[email protected]:2550]
[INFO] [09/16/2018 20:05:03.061] [main] [akka.remote.Remoting] Remoting now listens on addresses: [akka.tcp://[email protected]:2550]
remoteDb ==null :userremoteActor
[WARN] [SECURITY][09/16/2018 20:05:03.472] [LocalSystem-akka.remote.default-remote-dispatcher-8] [akka.serialization.Serialization(akka://LocalSystem)] Using the default Java serializer for class [com.lightbend.akka.sample.SetRequest] which is not recommended because of performance implications. Use another serializer or disable this warning using the setting 'akka.actor.warn-about-java-serializer-usage'
response :save success

看到了吧,客户端的控制台打印出服务端给出的响应信息:save success,再看服务端。打印出了客户端的actor路径,actorRef:

Actor[akka.tcp://[email protected]:2550/temp/$a],此时嘚瑟一下。

server start.......
[INFO] [09/16/2018 19:36:28.425] [main] [akka.remote.Remoting] Starting remoting
[INFO] [09/16/2018 19:36:29.262] [main] [akka.remote.Remoting] Remoting started; listening on addresses :[akka.tcp://[email protected]:2552]
[INFO] [09/16/2018 19:36:29.265] [main] [akka.remote.Remoting] Remoting now listens on addresses: [akka.tcp://[email protected]:2552]
actorRef : Actor[akka.tcp://[email protected]:2550/temp/$a]

至此,就完成了一次客户端对远程actor的请求,以及远程actor对客户端的响应的操作。手工~!!!!!!!!!!!!!!!

 

你可能感兴趣的:(akka网络编程)