zoukankan      html  css  js  c++  java
  • Akka实践一些总结

    最近在一些服务中使用了akka,主要用来做异步解耦和本地消息分发(路由),这里简单总结一下用法.

    与spring集成

    网上有不少集成的例子,要使用到spring的扩展.
    我这边没有这样处理,而是简单把ActorSystem创建的actor的过程放在了spring configuration里,把ActorRef作为bean,毕竟actor本身不能为单例但是ref可以.

    actor要使用一些bean的话就全部都由构造函数传入.
    如下:

    public class UserActor extends AbstractLoggingActor {
    
        private UserService userService;
    
        public static Props props(UserService userService) {
            return Props.create(UserActor.class, () -> new UserActor(userService));
        }
    
        public UserActor(UserService userService) {
            this.userService = userService;
        }
    

    在java中使用

    使用中能感觉和java还是有些隔阂的...
    特别是容器(Collection)之间的转换和处理.
    给出一些例子,可能是我没发现更方便的写法..

    List<Routee> routees = new ArrayList<>();
    senders.forEach(e -> {
                try {
                    ActorRef ref = getContext().actorOf(createdProps.apply(e), prefix + "-" + e.getId());
                    routees.add(new ActorRefRoutee(ref));
                } catch (InvalidActorNameException ex) {
                    log().error(ex, "name already in use");
                }
            });
    router = new Router(new RoundRobinRoutingLogic(), routees);
    

    这边本来用一个map就能解决了,但会要求类型强转Router的第二个参数是java.lang.Iterable<Routee>而不是java.lang.Iterable<? extends Routee>(ActorRefRoutee是其子类),再加上还要处理重名错误,还是用了这种错误的forEach使用方式.

        private void stopRoutee(Router router) {
            List<Routee> routees = new ArrayList<>(seqAsJavaList(router.routees()));
            routees.forEach(e -> {
                ActorRefRoutee ae = (ActorRefRoutee) e;
                ActorRef ref = ae.ref();
                // 移除这个routee
                router.removeRoutee(ae);
                // 停止这个ref
                context().stop(ref);
            });
        }
    

    router.routees()返回的是个IndexSeq...和java的没有兼容和对应.
    最开始找了一些,后来发现有scala.collection.JavaConversions可以做兼容...感受到了隔阂.

    此外ask模式,akka为java提供了PatternsCS.这个类返回的是java的CompletionStage类型相比Patterns,比较友好.

    使用误区

    最容易误用的一点就是消息处理中有阻塞操作,比如直接在actor中进行数据库操作和处理网络请求,而使用的actor也没有和线程绑定,这种情况需要使用额外的线程池,这个其实和用netty是一样的情况,用来进行应用调度的线程数有限.

    由于上面提到的点,于是在actor内可能就会存在一些回调,一不小心就可能直接调用/改变actor内部的状态(例如在回调直接访问field).

    private List<String> list;
    ... ...
    public Receive createReceive() {
        return receiveBuilder()
                .match(Message.class, e -> xxxx.onSuccess(r -> list.add(r)))
                ... ...
    

    这样等于内部状态被多线程访问,破坏了actor内部的状态,正确的做法是在回调中给自己发送消息.

  • 相关阅读:
    WPF 调用WINForm中的ColorDialog
    WPF 获取ControlTemplate 中的控件方法
    <转> 8个超棒的免费高质量图标搜索引擎
    WPF 右键菜单动画
    WPF 创建超级连接
    WPF 数据模板的切换简单事例
    WPF 关于ShowDialog后主窗体依然能响应键盘输入法的解决方案。
    <转>强制类型转换总结
    WPF 中的MessageBox返回值获取并判断
    WPF数据绑定实现自定义数据源
  • 原文地址:https://www.cnblogs.com/fairjm/p/10035181.html
Copyright © 2011-2022 走看看