Java `“@Autowired”依赖项上的NullPoinerException”

Java `“@Autowired”依赖项上的NullPoinerException”,java,spring,spring-boot,Java,Spring,Spring Boot,这是我的第一个Spring应用程序,请原谅我对此事的无知 我在一个@Autowired依赖项上得到了一个NullPoinerException 14:08:48,415 SEVERE [com.vaadin.server.DefaultErrorHandler] (default task-4) : java.lang.NullPointerException at com.letifer.ui.factory.BudgetTabbedPaneFactory$BudgetTabbedPane.i

这是我的第一个
Spring
应用程序,请原谅我对此事的无知

我在一个
@Autowired
依赖项上得到了一个
NullPoinerException

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

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

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

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

}
此类还有另外两个依赖项,
BudgetCountMenuFactory
BudgetInfoPaneFactory

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

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

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

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

}
我的无知使我相信“嵌套”依赖项(一个
@Autowired
组件中的
@Autowired
组件)可以正常工作

但很明显,我在顶部组件上得到了一个
NullPoinerException

我错过了什么?


什么是“在依赖项中注入依赖项”的智能方式?

好吧,我认为我们需要在春季澄清什么是依赖项注入

  • 当您使用注释标记类时,
    @SpringComponent
    @Controller
    @Repository
    等,spring会自动创建该类的实例。但这将不是
    BudgetTabbedPaneFactory
    ,而是动态生成的
    BudgetTabbedPaneFactory
    (所谓)的子类
  • 实例化之后,所有带注释的组件对于Spring都可见。它们位于
    Spring上下文中
    ,成为
    托管bean
  • 然后Spring检查所有标记为
    @Autowired
    的方法和字段,并尝试使用前一阶段自动创建的对象的适当实例初始化它们
  • 但是,当您手动创建对象时,它将存在于
    Spring上下文之外,Spring将不关心它及其注释。它其实根本不了解你的班级。只是一种标记,它们本身不执行任何功能

    阅读关于的章节。也许这将有助于为您的任务找到最佳解决方案


    另外,对于您的情况,您至少应该将
    @SpringComponent
    注释置于
    BudgetTabbedPane
    之上(不确定它是否适用于内部类),因为现在它不是Springbean,也不需要手动创建它来让Spring为您的,我认为我们需要在春季澄清什么是依赖注入

  • 当您使用注释标记类时,
    @SpringComponent
    @Controller
    @Repository
    等,spring会自动创建该类的实例。但这将不是
    BudgetTabbedPaneFactory
    ,而是动态生成的
    BudgetTabbedPaneFactory
    (所谓)的子类
  • 实例化之后,所有带注释的组件对于Spring都可见。它们位于
    Spring上下文中
    ,成为
    托管bean
  • 然后Spring检查所有标记为
    @Autowired
    的方法和字段,并尝试使用前一阶段自动创建的对象的适当实例初始化它们
  • 但是,当您手动创建对象时,它将存在于
    Spring上下文之外,Spring将不关心它及其注释。它其实根本不了解你的班级。只是一种标记,它们本身不执行任何功能

    阅读关于的章节。也许这将有助于为您的任务找到最佳解决方案


    注意:对于您的情况,您至少应该将
    @SpringComponent
    注释置于
    BudgetTabbedPane
    之上(不确定它是否适用于内部类),因为现在它不是Spring bean,所以不要手动创建它来让Spring为您的应用程序注入依赖项。

    当您使用
    new
    创建一个对象时,就像您在这里所做的
    new BudgetInfoPaneLayout()
    那样,该对象将没有任何Spring管理的内容,比如注入的对象和属性-它们将为空。与其用new创建对象,不如将它们注入类。@csm\u dev这应该是问题的答案:)@csm\u dev我的假设是,我不需要由
    Spring
    管理它,因为它是一个内部类,其他依赖项使用相同的
    builder模式,但没有“嵌套依赖项”注入时没有任何问题。当您像此处那样使用
    new
    创建对象
    new BudgetInfoPaneLayout()
    时,该对象将不会有任何Spring管理的内容,如注入的对象和属性-它们将为空。与其用new创建对象,不如将它们注入类。@csm\u dev这应该是问题的答案:)@csm\u dev我的假设是,我不需要由
    Spring
    管理它,因为它是一个内部类,其他依赖项使用相同的
    builder模式,但没有“嵌套依赖项”注入没有任何问题。很好地注释内部类并注入它们解决了问题。。。我理解这个概念,但是代码中仍然有
    new
    类型的组件创建li
    new VerticalLayout()
    并且它可以工作,我不理解为什么?因为该类内部没有任何spring管理的组件。是的,@csm\u dev是正确的。换句话说,如果类中有一些Spring注释(
    @Autowired
    @SpringComponent
    ),则必须由Spring实例化。尝试将一些
    @Autowired
    属性添加到
    BudgetAccountMenuLayout
    BudgetInfoPaneLayout
    中,并在
    init()中访问它。您还将获得
    NullPointerException
    。很好地注释内部类并注入它们解决了问题。。。我理解这个概念,但是代码中仍然有
    new
    类型的组件创建li
    new VerticalLayout()
    并且它可以工作,我不理解为什么?因为该类内部没有任何spring管理的组件。是的,@csm\u dev是正确的。换句话说,如果你有