当前位置: 首页 > 知识库问答 >
问题:

如何将自定义域的注入添加到FXMLLoader的默认ControllerFactory中?

顾赞
2023-03-14

我想在控制器的initialize方法在创建时被自动调用之前,在控制器中设置一些非UI字段。据我所知,这样做的方法是提供自定义的ControllerFactory,因为ControllerFactory返回创建的对象后调用Initialize()。我想按照这个答案使用以下代码:

FXMLLoader loader = new FXMLLoader(mainFXML); // some .fxml file to load
loader.setControllerFactory(param -> {
    Object controller = null;
    try {
        controller = ReflectUtil.newInstance(param); // this is default behaviour
    } catch (InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
    }
    if (controller instanceof Swappable) {
        ((Swappable) controller).setSwapper(swapper); // this is what I want to add
    }
    return controller;
});

但是,Reflectutil类(在默认的SetControllerFactory方法中使用)是com.sun.reflect.misc包的一部分,我不能使用它,因为编译失败并出现错误:package sun.reflect.misc不存在

据我所知,我不能使用sun软件包,因为这不是公共API。所以问题是:我该怎么办?我找不到任何其他这样的例子,只有带有ReflectUtil的例子,我希望我的ControllerFactory使用@fxml注释来遵守JavaFX的默认工作流,比如Jodd Petite这样的其他DI框架可以吗?是否有其他方法来设置字段?(除了在它上进行同步并在initialize()中等待,直到setter方法从其他线程调用)。github上完整的上下文代码。

共有1个答案

乐正浩博
2023-03-14

如果希望通过反射创建实例,则需要使用class.getConstructor(class...)1,后面跟着Constructor.newInstance(object...)

FXMLLoader loader = new FXMLLoader(/* some location */);
loader.setControllerFactory(param -> {
    Object controller;
    try {
        controller = param.getConstructor().newInstance();
    } catch (ReflectiveOperationException ex) {
        throw new RuntimeException(ex);
    }
    if (controller instanceof Swappable) {
        ((Swappable) controller).setSwapper(swapper);
    }
    return controller;
}

此代码要求controller类具有公共的无参数构造函数。如果希望通过构造函数注入依赖项,可以执行如下操作:

FXMLLoader loader = new FXMLLoader(/* some location */);
loader.setControllerFactory(param -> {
    Object controller;
    try {
        if (Swappable.class.isAssignableFrom(param)) {
            controller = param.getConstructor(Swapper.class).newInstance(swapper);
        } else {
            controller = param.getConstructor().newInstance();
        }
    } catch (ReflectiveOperationException ex) {
        throw new RuntimeException(ex);
    }
    return controller;
}

此代码假定swappable的所有子类都有一个接受swapper的公共单参数构造函数。

如果要获得非公共构造函数,则需要使用constructor.getDeclaredConstructor(class..)。然后,在调用构造函数之前,需要调用setaccessible(true)

如果使用Jigsaw模块(Java9+)和此控制器工厂代码与控制器类不在同一个模块中,请记住一些事情。假设控制器工厂代码位于模块foo中,控制器类位于模块bar中:

  • 如果使用带有公共构造函数的公共控制器,则bar必须将控制器类的包至少导出到foo
  • 如果使用非公共控制器和/或构造函数,则必须执行相同的操作,但使用打开而不是导出

1。如果使用无参数(不一定是公共的)构造函数,则可以绕过getConstructor,直接调用class.newinstanage()。但是,请注意,该方法存在一些问题,并且从Java9.开始就不推荐使用了

 类似资料:
  • 我创建了一个带有react和firebase身份验证的应用程序,我希望在注册/登录期间,我只需要输入“用户名”。 “用户名”@mydefaultdomain。通用域名格式

  • 如果我创建一个提供者并将其绑定到一个类,就像这样 然后

  • 如果我没有在结构中定义构造函数,我可以通过如下方式选择某个值来初始化它: 但是如果我添加新的默认构造函数,那么我就会失去这个功能: 两种方式都有可能吗? 我尝试添加默认构造函数,但似乎也不起作用。

  • 问题内容: 我正在尝试使用自定义类加载器进行练习,并且有一些问题。有没有一种方法可以指示JVM在全球范围内使用我的自定义类加载器?例如,我写了一个在Tomcat 6下运行的小型应用程序。该servlet由容器管理,应在哪里设置类加载器?另外,Web应用程序使用了一些3rd party jars,我可以控制这些jars的类加载吗? 对于独立应用程序,以上答案是否会有所不同? 谢谢! 问题答案: 您可

  • 我目前正在从事一个Spring boot(webflux)项目,在该项目中,我们使用Spring boot-actuator依赖关系在/actuator/prometheusendpoint上公开了我们的应用程序的指标,默认情况下,该依赖关系为我们提供了例如:http\u server\u requests\u seconds\u bucket metric。默认情况下,它有{exception=

  • 我使用Dropwizard Metrics library记录我的应用程序中各种操作的时间,使用计时器和控制台报告器,并将计数、平均速率等记录到控制台fine。 我希望这些数字也可以在 /metricsservlet上使用,并且基于http://metrics.dropwizard.io/3.1.0/manual/servlets/我需要访问名为的Metric注册表。但是查看文档和代码,我看不到是