2016-11-11 1 views
7

JavaFX 런타임은 Application 개체와 모든 컨트롤러 개체를 인스턴스화하려고하므로 이러한 개체에 종속성을 어떻게 주입합니까?종속성 삽입 및 JavaFX

개체가 Spring과 같은 DI 프레임 워크로 인스턴스화 된 경우 프레임 워크는 모든 종속성을 철회합니다. 개체를 수동으로 인스턴스화하는 경우에는 생성자 매개 변수를 통해 종속성을 제공합니다. 하지만 JavaFX 응용 프로그램에서 무엇을합니까?

감사합니다.

답변

11

FXMLLoader에 대해 controller factory을 지정할 수 있습니다. 컨트롤러 팩토리는 컨트롤러 클래스를 컨트롤러로 사용할 객체 (아마도 그 클래스의 인스턴스 일 수도 있지만 반드시 그런 것은 아님)에 매핑하는 함수입니다.

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... 
// ... 

그리고 지금 FXMLLoadercontext.getBean(c);를 호출하여 Class<?> c에 대한 컨트롤러의 인스턴스를 생성합니다 :

그래서 당신은 봄 당신을위한 컨트롤러의 인스턴스를 만들려면,이처럼 간단 할 수있다. 당신이 DI 프레임 워크를 사용하지 않는 경우

@Configuration 
public class AppConfig { 

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

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

    // ... 
} 

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(...); 
    } 
} 

과 함께, 당신은 "손으로"주사를 수행 할 :

그래서, 예를 들어, 당신은 구성을 가질 수있다 , 그렇게 할 수는 있지만 상당히 많은 것을 반영해야합니다. 체크 아웃 할 수 있습니다,

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(); 
// ... 

을 한 후 바로

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(...); 
    } 
} 

마지막으로 수행 다음은 방법을 보여줍니다 (당신에게 얼마나 추악한 일 봄 당신을 위해하고있는의 아이디어를 줄 것이다!) afterburner.fx은 매우 가볍고 (모든 최선의 방법으로) JavaFX 관련 DI 프레임 워크입니다. (이는 컨벤션 오버 구성 방식을 사용합니다. FXML 파일 이름과 컨트롤러 클래스 이름 및 CSS 파일 이름을 일치 시키면 모든 것이 작동합니다.)

관련 문제