`@Autowired`依赖的`NullPoinerException`

时间:2017-06-15 11:31:23

标签: java spring spring-boot

这是我的第一个Spring申请,请原谅我对此事的无知。

我在NullPoinerException依赖项上获得@Autowired

14:08:48,415 SEVERE [com.vaadin.server.DefaultErrorHandler] (default task-4) : java.lang.NullPointerException
at com.letifer.ui.factory.BudgetTabbedPaneFactory$BudgetTabbedPane.init(BudgetTabbedPaneFactory.java:26)
at com.letifer.ui.factory.BudgetTabbedPaneFactory.createComponent(BudgetTabbedPaneFactory.java:44)
at com.letifer.ui.commons.BudgetMainUI.init(BudgetMainUI.java:44)

BudgetTabbedPaneFactory.java:

package com.letifer.ui.factory;

import org.springframework.beans.factory.annotation.Autowired;

import com.letifer.utils.constants.BudgetStringConstants;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.VerticalLayout;

@SpringComponent
public class BudgetTabbedPaneFactory implements BudgetComponent {

    private class BudgetTabbedPane extends VerticalLayout {

        private TabSheet tabSheet;

        @Autowired
        BudgetAccountsFactory accountsFactory;

        Component accounts;

        public BudgetTabbedPane init() {
            tabSheet = new TabSheet();
            accounts = accountsFactory.createComponent(); // <-- NullPoinerException
            return this;
        }

        public BudgetTabbedPane layout() {
            setSizeFull();
            tabSheet.addTab(accounts, BudgetStringConstants.ACCOUNTS_TAB_NAME.getName());
            tabSheet.addTab(new Label(BudgetStringConstants.BALANCE_TAB_NAME.getName()), BudgetStringConstants.BALANCE_TAB_NAME.getName());
            tabSheet.addTab(new Label(BudgetStringConstants.STATISTICS_TAB_NAME.getName()), BudgetStringConstants.STATISTICS_TAB_NAME.getName());

            addComponent(tabSheet);

            return this;
        }

    }

    public Component createComponent() {
        return new BudgetTabbedPane().init().layout();
    }

}

此类具有BudgetAccountsFactory依赖关系

BudgetAccountsFactory.java:

package com.letifer.ui.factory;

import org.springframework.beans.factory.annotation.Autowired;

import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;

@SpringComponent
public class BudgetAccountsFactory implements BudgetComponent {

    @Autowired
    private BudgetAccountMenuFactory accountMenuFactory;

    @Autowired
    private BudgetInfoPaneFactory infoPaneFactory;

    private class BudgetAccountsLayout extends HorizontalLayout {

        Component menu;
        Component infoPane;

        public BudgetAccountsLayout init() {

            menu = accountMenuFactory.createComponent();
            infoPane = infoPaneFactory.createComponent();

            return this;
        }

        public BudgetAccountsLayout layout() {

            setMargin(true);
            setSizeFull();

            addComponent(menu);
            setComponentAlignment(menu, Alignment.TOP_LEFT);
            setExpandRatio(menu, 1);

            addComponent(infoPane);
            setComponentAlignment(infoPane, Alignment.TOP_LEFT);
            setExpandRatio(infoPane, 2);

            return this;
        }

    }

    public Component createComponent() {
        return new BudgetAccountsLayout().init().layout();
    }

}

此课程还有另外2个家属,BudgetAccountMenuFactoryBudgetInfoPaneFactory

BudgetAccountMenuFactory.java:

package com.letifer.ui.factory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.letifer.utils.constants.BudgetStringConstants;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.ui.Component;
import com.vaadin.ui.ListSelect;
import com.vaadin.ui.VerticalLayout;

@SpringComponent
public class BudgetAccountMenuFactory implements BudgetComponent {

    private class BudgetAccountMenuLayout extends VerticalLayout {

        private ListSelect<String> options;

        public BudgetAccountMenuLayout init() {
            options = new ListSelect<String>(BudgetStringConstants.ACCOUNTS_MENU_OPTION_TITLE.getName());
            List<String> optionsList = new ArrayList<String>(Arrays.asList(BudgetStringConstants.ACCOUNTS_MENU_OPTION_SHOW_ACCOUNTS.getName(),
                    BudgetStringConstants.ACCOUNTS_MENU_OPTION_ADD.getName(), BudgetStringConstants.ACCOUNTS_MENU_OPTION_REMOVE.getName()));
            Set<String> optionsSet = new HashSet<String>(optionsList);
            options.setValue(optionsSet);
            return this;
        }

        public BudgetAccountMenuLayout layout() {
            setMargin(true);
            setSizeFull();

            addComponent(options);
            return this;
        }

    }

    public Component createComponent() {
        return new BudgetAccountMenuLayout().init().layout();
    }

}

BudgetInfoPaneFactory.java:

package com.letifer.ui.factory;

import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;

@SpringComponent
public class BudgetInfoPaneFactory implements BudgetComponent {

    private class BudgetInfoPaneLayout extends VerticalLayout {

        public static final String VIEW_NAME = "info";

        private Label label;

        public BudgetInfoPaneLayout init() {
            label = new Label("INFO HERE");
            return this;
        }

        public BudgetInfoPaneLayout layout() {
            setMargin(true);
            setSizeFull();
            addComponent(label);
            return this;
        }

    }

    public Component createComponent() {
        return new BudgetInfoPaneLayout().init().layout();
    }

}

我的无知使我相信&#34;嵌套&#34;依赖项(@Autowired组件中的@Autowired组件)可以正常工作。

但显然我在顶级组件上得到NullPoinerException

我在这里缺少什么?

什么是智能方式&#34;在依赖项中注入依赖项&#34;

1 个答案:

答案 0 :(得分:2)

好吧,我认为我们需要澄清什么是Spring中的依赖注入。

  1. 当您使用注释@SpringComponent@Controller@Repository等标记类时,spring会自动创建此类的实例。但这不是BudgetTabbedPaneFactory,而是动态生成BudgetTabbedPaneFactory的子类(所谓的Proxy)。
  2. 实例化后,所有带注释的组件对于Spring都是可见的。它们位于Spring context并成为managed beans
  3. 然后Spring检查标有@Autowired的所有方法和字段,并尝试使用前一阶段自动创建的对象的相应实例对它们进行初始化。
  4. 但是当你手动创建对象时,它将存在于Spring context之外,而Spring将不关心它及其注释。它实际上根本不了解你的课程。 Annotations只是他们自己不执行任何功能的标记。

    阅读有关Spring IoC container的部分。也许它有助于为您的任务找到最佳解决方案。

    P.S。对于你的情况,你应该至少把@SpringComponent注释放在BudgetTabbedPane上(不确定它是否适用于内部类),因为现在它不是Spring bean而不是手动创建它以让Spring注入依赖项您的。