JavaFX8 - 使用Guice进行线程任务

时间:2015-04-04 11:59:10

标签: java multithreading javafx-8 guice

我是Guice和JavaFX的新手(非常新)。我正在构建一个具有侦听套接字连接的线程的应用程序,并且在收到事件后,ObservableArrayList()上的线程存储值和应用程序将通知它们给用户。

我的问题是如何构造所有这些行为,以及如何从线程和JavaFX控制器“共享”ObservableList。

我正在阅读Guice,它可以帮助解耦new对象的创建。

我尝试设置一些东西,但是我的可运行任务上的@Inject属性为null:

Guice模块:

public class AppGuiceModule extends AbstractModule{

    @Override
    protected void configure() {
        bind(EventsDAO.class).toInstance(new EventsDAO());
    }

}

EventsDAO(具有ObservableArrayList)

@Singleton
public class EventsDAO {
     private ObservableList<ScheduledEvent> localCache = FXCollections.observableArrayList();

     public void addEvent(ScheduledEvent event) {
         localCache.add(event);
     }

     public void removeEvent(ScheduledEvent event) {
         this.localCache.remove(event);
     }
}

有两个,我在我的主要我去创建注射器:

@Override
    public void start(Stage stage) throws Exception {

        Injector injector = Guice.createInjector(new AppGuiceModule());

        Platform.setImplicitExit(false);

        Thread t = new Thread(new EventsReceiverTask());
        t.start();
        .....

现在,在Runnable对象中,我想@Inject EventsDAO(保存新事件)和@Inject也在我的Controller中,向localCache添加一个监听器(是localCache是​​私有的,我将提供一个getter)。 / p>

可运行的对象:

public class EventsReceiverTask implements Runnable {

    private static final int port = 4020;

    @Inject
    EventsDAO eventsDao; // This is null, why not injected ?

    private ServerSocket serverSocket;
    private Stage notificationStage;

    public EventsReceiverTask() {
        try {
            this.serverSocket = new ServerSocket(port);
            this.notificationStage = new Stage();

            eventsDao.addEvent(new ScheduledEvent());
        } catch (IOException ex) {
            Logger.getLogger(EventsReceiverTask.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

我不知道这是否是在JavaFX中实现“生产者 - 消费者”的正确方法,但我不知道如何使用所有静态方法分享这些组件,而不用创建繁琐的getter和setter。

2 个答案:

答案 0 :(得分:4)

您的问题确切地说明了为什么在可能的情况下不在依赖注入系统中使用new 的原因。

仅在注射框架是创建对象的框架时才会发生注射。当您致电new时,正在创建它们,不是框架

让Guice为您创建一个对象有两种方法:

  1. 使用injector.getInstance(Foo.class);
  2.   

    通过控制反转,流程取决于程序执行期间构建的对象图。通过抽象定义对象交互,可以实现这种动态流程。

    1. 让Guice为您创建您的对象作为注射。
      • 这正是@Inject注释的作用;指示Guice在绑定的类中为您创建对象。
    2. 一般来说,名称为EventsReceiverTask的类不是您希望在main方法中创建的顶级类。它们的名称更像EventService,您可以为其注入能够为您创建新任务的Provider<EventsReceiverTask>,所有这些都将正确地注入您的EventsDAO


      旁注:你没有问过这个,但是当你这样做时,在你的模块中:

      bind(EventsDAO.class).toInstance(new EventsDAO());
      

      覆盖了您尝试使用类定义中的@Singleton注释指定的绑定的范围。如果您希望此对象实际上是单例,则您还必须在模块中指定@Singleton绑定,例如

      bind(EventsDAO.class).toInstance(new EventsDAO()).in(Singleton.class);
      

      From the documentation:

        

      如果类型和bind()语句中的范围存在冲突,则将使用bind()语句的范围。如果某个类型使用您不想要的范围进行注释,请将其绑定到Scopes.NO_SCOPE

答案 1 :(得分:0)

您永远不会将成员字段注入任务对象,因此该值为null。

你需要类似下面的注入部分,以便Guice实际注入字段值。您可能希望进一步重构以使其更好,但在最基本的层面上,Guice不会注入该字段,直到您告知它为止。

public void start(Stage stage) throws Exception {

    Injector injector = Guice.createInjector(new AppGuiceModule());

    Platform.setImplicitExit(false);

    EventsReceiverTask task = new EventsReceiverTask();

    // You need something like this so that Guice injects the members into the object.
    injector.injectMembers(task);

    Thread t = new Thread(task);
    t.start();
    ....