根据Play框架

时间:2016-10-20 00:43:58

标签: java playframework dependency-injection akka guice

我跟踪数据库中consumerId的服务提供商列表。

我有SchedulerActorTaskActor启用的每个服务提供商创建consumerId

我想为列表中的每个服务提供商注入ServiceProviderTaskActor的实现。 ServiceProvider可以有不同的实现。

interface ServiceProvider {
    void processRequest(Request request);
}

class SchedulerActor {
     @Override
     public void onReceive(Object consumerId) throws Exception {
         List<String> serviceProvidersList = getFromDatabase((String) consumerId);
         for (String serviceProviderStr : serviceProvidersList) {

              //serviceProviderStr could be "ServiceProvider1" or "ServiceProvider2" 
              ServiceProvider serviceProvider = getServiceProviderFromStr(serviceProviderStr); 

              ActorRef r = getContext().actorOf(Props.create(TaskActor.class, serviceProvider));
              getContext().watch(r);
              routees.add(new ActorRefRoutee(r));

         }
         router = new Router(new BroadcastRoutingLogic(), routees);
         router.route(message, getSelf());
     }
}

class TaskActor {
    private final ServiceProvider serviceProvider;
    public TaskActor(ServiceProvider serviceProvider) {
        this.serviceProvider = serviceProvider;
    }

    @Override
    public void onReceive(Object message) {
        if (message instanceof Request) {
            serviceProvider.processRequest((Request)message);
        }
    }
}
  1. getServiceProviderFromStr(String)内部有什么来实现这个目标?
  2. 我不想添加switchif else语句来返回所需的实现。
  3. 我可以在运行时提供Provider Bindings,将字符串传递给提供者对象吗?

3 个答案:

答案 0 :(得分:1)

使用Guice AssistedInject,即FactoryModuleBuilder向TaskActor构造函数添加服务名称的String参数,并使用此参数注入带有@Named注释的ServiceProvider:

  1. 在模块中定义工厂界面:

    public interface TaskActorFactory{
        TaskActor create(String serviceName);
    }
    
  2. 在模块 configure 方法中安装工厂并注册服务绑定:

    protected void configure() {
        bind(ServiceProvider.class).annotatedWith(Names.named("serviceA")).to(ServiceA.class);
        bind(ServiceProvider.class).annotatedWith(Names.named("serviceB")).to(ServiceB.class);
        bind(ServiceProvider.class).annotatedWith(Names.named("serviceC")).to(ServiceC.class);
        install(new FactoryModuleBuilder()
            .implement(TaskActor.class, TaskActor.class)
            .build(TaskActorFactory.class));
     }
    
  3. 实施TaskActor:

    @Inject 
    class TaskActor extends UntypedActor {
    
        public static Props props(String serviceName) {
            return Props.create(TaskActor.class, ()->new TaskActor(serviceName));
        }
    
        private final ServiceProvider serviceProvider;
    
        public TaskActor(Injector injector, @Assisted String serviceName) {
            serviceProvider = injector.getInstance(Key.get(ServiceProvider.class, Names.named(serviceName)));
        }
        ...
    }
    
  4. 从SchedulerActor创建TaskActor

    @Override
    public void onReceive(Object consumerId) throws Exception {
         List<String> serviceProvidersList = getFromDatabase((String) consumerId);
         for (String serviceProviderStr : serviceProvidersList) {
             ActorRef r = getContext().actorOf(TaskActor.props(serviceProviderStr));
             getContext().watch(r);
             routees.add(new ActorRefRoutee(r));
         }
         ...
     }
    

    }

答案 1 :(得分:1)

使用相同命名绑定而不是建议@Assisted

的另一种方法
@Inject 
public Injector injector;
...
ServiceProvider s = injector.getInstance(Key.get(Parent.class, Names.named(serviceName)));

其中绑定在configure()中的类:

bind(ServiceProvider.class).annotatedWith(Names.named("Name1")).to(Child1.class);
bind(ServiceProvider.class).annotatedWith(Names.named("Name2")).to(Child2.class);

答案 2 :(得分:0)

如果您不想使用pydev_file_utils.pyc switch,我认为您必须使用反射来执行此操作,其中if else是类名。

serviceProviderStr

请记住,您可以通过调用 private ServiceProvider getServiceProviderFromStr(String serviceProviderClassName){ try { Class<?> clazz = Class.forName(serviceProviderClassName); if(!ServiceProvider.class.isAssignableFrom(clazz)){ throw new IllegalArgumentException("Argument is not a ServiceProvider class."); } Class<? extends ServiceProvider> serviceProviderClass = (Class<? extends ServiceProvider>) clazz; return serviceProviderClass.newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } return null; } 来获取课程名称。