2016-11-11 24 views
7

Ponieważ środowisko wykonawcze JavaFX chce utworzyć instancję Mój obiekt aplikacji i wszystkie moje obiekty kontrolerów, w jaki sposób wstrzyknąć zależności do tych obiektów?Wstrzykiwanie zależności i JavaFX

Jeśli obiekty zostały utworzone za pomocą frameworka DI, tak jak Spring, struktura ta połączy wszystkie zależności. Gdybym tworzył obiekty ręcznie, dostarczałbym zależności za pomocą parametrów konstruktora. Ale co mam zrobić w aplikacji JavaFX?

Dzięki!

Odpowiedz

11

Można określić controller factory dla FXMLLoader. Fabryka kontrolerów jest funkcją, która odwzorowuje klasę kontrolera na obiekt (prawdopodobnie, ale niekoniecznie instancję tej klasy), która będzie używana jako kontroler.

Więc jeśli chcesz Wiosna tworzyć instancje kontroler dla ciebie, to może być tak proste, jak:

ApplicationContext context = ... ; 

FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml")); 
loader.setControllerFactory(context::getBean); 
Parent root = loader.load(); 
SomeController controller = loader.getController(); // if you need it... 
// ... 

a teraz FXMLLoader będą tworzyć instancje kontrolerowi celem Class<?> c wywołując context.getBean(c);.

Tak, na przykład można mieć konfigurację:

@Configuration 
public class AppConfig { 

    @Bean 
    public MyService service() { 
     return new MyServiceImpl(); 
    } 

    @Bean 
    @Scope("prototype") 
    public SomeController someController() { 
     return new SomeController(); 
    } 

    // ... 
} 

z

public class SomeController { 

    // injected by FXMLLoader: 
    @FXML 
    private TextField someTextField ; 

    // Injected by Spring: 
    @Inject 
    private MyService service ; 

    public void initialize() { 
     someTextField.setText(service.getSomeText()); 
    } 

    // event handler: 
    @FXML 
    private void performAction(ActionEvent e) { 
     service.doAction(...); 
    } 
} 

Jeśli nie używasz ramy DI, a chcesz zrobić zastrzyk "ręcznie" , możesz to zrobić, ale wymaga to sporo refleksji. Poniżej przedstawiono w jaki sposób (i daje wyobrażenie o ile brzydki praca Wiosna robi dla Ciebie!):

FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml")); 
MyService service = new MyServiceImpl(); 
loader.setControllerFactory((Class<?> type -> { 
    try { 
     // look for constructor taking MyService as a parameter 
     for (Constructor<?> c : type.getConstructors()) { 
      if (c.getParameterCount() == 1) { 
       if (c.getParameterTypes()[0]==MyService.class) { 
        return c.newInstance(service); 
       } 
      } 
     } 
     // didn't find appropriate constructor, just use default constructor: 
     return type.newInstance(); 
    } catch (Exception exc) { 
     throw new RuntimeException(exc); 
    } 
}); 
Parent root = loader.load(); 
// ... 

a potem po prostu zrobić

public class SomeController { 

    private final MyService service ; 

    public SomeController(MyService service) { 
     this.service = service ; 
    } 

    // injected by FXMLLoader: 
    @FXML 
    private TextField someTextField ; 

    public void initialize() { 
     someTextField.setText(service.getSomeText()); 
    } 

    // event handler: 
    @FXML 
    private void performAction(ActionEvent e) { 
     service.doAction(...); 
    } 
} 

Wreszcie może chcesz sprawdzić afterburner.fx, która jest bardzo lekką (we wszystkich najlepszych metodach) architekturą DI specyficzną dla JavaFX. (Wykorzystuje podejście oparte na konwencji, w którym dopasowujesz nazwy plików FXML do nazw klas kontrolerów i opcjonalnie nazwy plików CSS, a wszystko po prostu działa.)

Powiązane problemy