Java 使用Vaadin和Spring Boot实现依赖项注入的良好实践

Java 使用Vaadin和Spring Boot实现依赖项注入的良好实践,java,spring-mvc,spring-boot,dependency-injection,vaadin,Java,Spring Mvc,Spring Boot,Dependency Injection,Vaadin,我有以下问题:我得到了一个扩展UI的Mainview类。在这个类中,依赖注入起作用。但是这个类拥有一个带有视图的导航器。此视图包含也包含视图的选项卡页。现在我需要在视图中注入一个Spring@Service类。但是DI链断了。我已经知道依赖注入链不应该被打断(我通过这里的另一个问题发现了这一点)。但我找不到办法让这条链子活下去。有人有一个很好的技巧,如何实现的意见being也注入,尽管如此,我可以使用任何地方的导航器?我觉得我做的太复杂了,甚至是做错了。这是我的Mainview(扩展UI)类:

我有以下问题:我得到了一个扩展UI的Mainview类。在这个类中,依赖注入起作用。但是这个类拥有一个带有视图的导航器。此视图包含也包含视图的选项卡页。现在我需要在视图中注入一个Spring@Service类。但是DI链断了。我已经知道依赖注入链不应该被打断(我通过这里的另一个问题发现了这一点)。但我找不到办法让这条链子活下去。有人有一个很好的技巧,如何实现的意见being也注入,尽管如此,我可以使用任何地方的导航器?我觉得我做的太复杂了,甚至是做错了。这是我的Mainview(扩展UI)类:

现在是客户端创建视图:

@SpringView(name = ClientCreationView.VIEW_NAME)
@ViewScope
public class ClientCreationView extends VerticalLayout implements View {


private static final long serialVersionUID = 1L;
public static final String VIEW_NAME = "client_creationview";
private final Logger LOGGER = LoggerFactory.getLogger(ClientCreationView .class);

@Autowired
private TabSheet tabsheet;

@Autowired
private ClientCredentialFormular clientCredentialFormular;

@Autowired
private ClientRegisterFormular clientRegisterFormular;

public ClientCreationView(){
    LOGGER.info("Initializing ClientCreationView...");
    this.setCaption("Register New Client");
    LOGGER.info("Initializing ClientView...");
    setSizeFull();
    setSpacing(true);
    setMargin(true);
    //      TabSheet tabsheet = new TabSheet();
    this.addComponent(tabsheet);
    tabsheet.addTab(clientRegisterFormular);
    tabsheet.addTab(clientCredentialFormular);

}

@Override
public void enter(ViewChangeEvent event) {
    // Do nothing...

}

}
此视图的选项卡需要注入服务类:

@SpringView(name = ClientRegisterFormular.VIEW_NAME)
@ViewScope
public class ClientRegisterFormular extends VerticalLayout implements View {

private static final long serialVersionUID = 1L;
public static final String VIEW_NAME = "client_data_formular";
private static final Logger LOGGER = LoggerFactory.getLogger(ClientRegisterFormular.class);

@Autowired
IClientService clientService;

private TextField clientIdField = new TextField("Client-Id");
private TextField rootUriField = new TextField("Root-URI");
private TextField redirectUriField = new TextField("Redirect-URI");
private Button saveButton = new Button("Save");
private Button cancelButton = new Button("Cancel");
private FormLayout form = new FormLayout();
private SaveButtonListener saveButtonListener = new SaveButtonListener(this);
private CancelButtonListener cancelButtonListener = new CancelButtonListener(this);


public ClientRegisterFormular(){
    LOGGER.info("Initializing Client Data Formular...");
    this.setCaption("Client Data");
    this.setSizeFull();
    this.setSpacing(true);
    this.setMargin(true);
    /*
     * Panel for Formular:
     */
    Panel panel = new Panel("Register Client");
    panel.addStyleName("regFormPanel");
    panel.setSizeUndefined(); // Shrink to fit content

    //Formular:
    this.form.setMargin(true);
    this.form.setSizeFull();
    this.clientIdField.setWidth("900px");
    this.clientIdField.setRequiredIndicatorVisible(true);
    form.addComponent(clientIdField);
    this.rootUriField.setRequiredIndicatorVisible(true);
    this.rootUriField.setWidth("900px");
    form.addComponent(rootUriField);
    this.redirectUriField.setRequiredIndicatorVisible(true);
    this.redirectUriField.setWidth("900px");
    form.addComponent(redirectUriField);
    //TODO Checkboxes for

    //Button-Layout:
    HorizontalLayout buttonLayout = new HorizontalLayout();
    this.saveButton.addClickListener(saveButtonListener);
    buttonLayout.addComponent(this.saveButton);
    this.cancelButton.addClickListener(this.cancelButtonListener);
    buttonLayout.addComponent(this.cancelButton);
    buttonLayout.setComponentAlignment(this.saveButton, Alignment.TOP_LEFT);

    form.addComponent(buttonLayout);
    panel.setContent(form);
    this.addComponent(panel);
    //      this.addComponent(buttonPanel);
    this.setComponentAlignment(panel, Alignment.TOP_LEFT);

}

@Override
public void enter(ViewChangeEvent event) {
    // Do nothing..

}


private static class SaveButtonListener implements Button.ClickListener{

    private static final long serialVersionUID = 1L;
    private ClientRegisterFormular clientRegisterFormular;

    public SaveButtonListener(ClientRegisterFormular clientRegisterFormular){
        this.clientRegisterFormular = clientRegisterFormular;
    }

    @Override
    public void buttonClick(ClickEvent event) {
        LOGGER.info("Saving client...");
        Client newClient = new Client();
        newClient.setClientId(clientRegisterFormular.clientIdField.getValue());
        newClient.setRootUri(this.clientRegisterFormular.rootUriField.getValue());
        newClient.setRedirectUri(this.clientRegisterFormular.redirectUriField.getValue());
        newClient.setClientId(UUID.randomUUID().toString());
        this.clientRegisterFormular.clientService.createClient(newClient);
        refreshView();

    }

    public void refreshView() {
        MainView.navigator.navigateTo(ClientManagementView.VIEW_NAME);
    }

}

private static class CancelButtonListener implements Button.ClickListener{

    private static final long serialVersionUID = 1L;
    private ClientRegisterFormular clientRegisterFormular;

    public CancelButtonListener(ClientRegisterFormular clientRegisterFormular){
        this.clientRegisterFormular = clientRegisterFormular;
    }

    @Override
    public void buttonClick(ClickEvent event) {
        LOGGER.info("Canceling Client Creation...");
        refreshView();

    }


    public void refreshView() {
        MainView.navigator.navigateTo(ClientManagementView.VIEW_NAME);
    }

}

}

我认为问题出在ClientManagementView中,您正在创建两个视图:

tabsheet.addTab(new ClientOverview());
tabsheet.addTab(new ClientCreationView());
但是应该是spring创建这些视图,因为您将它们声明为@SpringView,并且希望注入其他bean

我认为您应该在ClientManagementView中自动关联它们:

@Autowired
ClientOverview clientOverview;

@Autowired
ClientCreationView clientCreationView;


tabsheet.addTab(clientOverview);
tabsheet.addTab(clientCreationView);

我解决了。问题不在于tabsheet不是spring组件(因为我在应用程序类中将它声明为wiht@bean)。问题是我没有通过构造函数自动连接它。通过将tabsheet设置为constructor的参数并在那里设置autowire,我解决了这个问题

好的,这是重点。我也已经尝试过了,但我得到了一个类似thins的异常:org.springframework.beans.factory.unsatifiedpendencyException:创建名为“clientManagementView”的bean时出错:通过字段“clientCreationView”表示的未满足的依赖关系;嵌套的异常是org.springframework.beans.factory.BeanCreationException:创建名为“clientCreationView”的bean时出错,该名称在文件[C:\mypath…]中定义:因此似乎此链已断开。但无论如何,这是一个很好的观点。注意:我在上面的代码中更新了这个,我认为这个@Autowired private TabSheet;可能是ClientCreationView中的问题。tabsheet是一个vaadin组件,而不是可以自动关联的弹簧组件。
tabsheet.addTab(new ClientOverview());
tabsheet.addTab(new ClientCreationView());
@Autowired
ClientOverview clientOverview;

@Autowired
ClientCreationView clientCreationView;


tabsheet.addTab(clientOverview);
tabsheet.addTab(clientCreationView);