【问题标题】:Autowiring not working in springboot application自动装配在 Spring Boot 应用程序中不起作用
【发布时间】:2018-03-10 14:25:18
【问题描述】:

我正在尝试使用 JFrame 创建一个 Spring Boot 应用程序。我可以在 applicationContext 中看到我的 bean,但它们没有自动装配。我无法找到此问题的原因。有人可以帮我弄这个吗?

代码如下:

JavauiApplication - 它显示 userManager 和 userNameRepository 都是 bean

@SpringBootApplication
public class JavauiApplication implements CommandLineRunner {

    @Autowired
    private ApplicationContext appContext;

    public static void main(String[] args) {
        new SpringApplicationBuilder(JavauiApplication.class).headless(false).run(args);

        java.awt.EventQueue.invokeLater(() -> new InputNameForm().setVisible(true));
    }

    @Override
    public void run(String... args) throws Exception {

        String[] beans = appContext.getBeanDefinitionNames();
        Arrays.sort(beans);
        for (String bean : beans) {
            System.out.println(bean);
        }

    }
}

InputNameForm.java -> userManager 即将为空

@Component
public class InputNameForm extends javax.swing.JFrame {

    /**
     * Creates new form InputNameForm
     */
    public InputNameForm() {
        initComponents();
    }

    @Autowired
    UserManager userManager;

    private void submitButtonActionPerformed(java.awt.event.ActionEvent evt) {
        userManager.setName(firstName.getText(), lastName.getText());
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(InputNameForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new InputNameForm().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField firstName;
    private javax.swing.JLabel firstNameLabel;
    private javax.swing.JTextField lastName;
    private javax.swing.JLabel lastNameLabel;
    private javax.swing.JButton submitButton;
    // End of variables declaration//GEN-END:variables
}

UserManager.java -> userNameRepository 即将为空

@Component
public class UserManager {

  @Autowired
  UserNameRepository userNameRepository;

  public void setName(String firstName, String lastName) {
    userNameRepository.save(new UserName(firstName, lastName));
    System.out.println(userNameRepository.findAllByFirstName(firstName));
  }
}

【问题讨论】:

  • 您使用新关键字自己创建InputNameForm 的实例。 Spring 不知道该实例,因此不会注入任何东西。
  • @dunni 我自动装配了 InputNameForm,现在它也变成了 null。
  • 它已修复。我将实例设为静态以在 void main 中调用。当我用 appContext.getBean(InputNameForm.class) 替换它时,一切正常

标签: spring swing spring-boot jframe


【解决方案1】:

这是一个非常常见的问题,因为新手不了解 IoC 容器的工作原理。

  1. 首先,BeanDefinitionReader 从 XML、注释(@Component@Service 等)、JavaConfig 或 Groovy 脚本中读取有关 bean 的元数据。
  2. 有几个 BeanPostProcessor 负责读取您正在编写的所有这些 Spring 注释(@Autowired 等)。
  3. BeanFactory 创建所有 BeanPostProcessor,然后创建所有 bean。

如果您通过new 运算符创建具有@Autowired 依赖项的bean 会发生什么?没什么,因为它实际上不是豆子。您创建的对象与 IoC 容器无关。如果你用@Component(例如)标记它,你的ApplicationContext 中可能已经有bean,但是通过new 运算符创建的对象不会被Spring 处理(注释不起作用)。

希望这会有所帮助。

PS:生命周期被简化了。

【讨论】:

    【解决方案2】:

    几天前我遇到了同样的问题。我所理解的是,像 netbeans 附带的 GUI 构建器将使用 new 关键字自动创建组件。这意味着这些组件不会由 spring 管理。代码通常是这样的:

    private void initComponents() {
        jPanel1 = new javax.swing.JPanel(); //This component will not be managed by spring.
        //...
    }
    

    您可以使用here 提供的以下类来使其工作。

    @Component
    public class BeanProvider {
        private static ApplicationContext applicationContext;
    
        // Autowires the specified object in the spring context
        public static void autowire(Object object) {
            applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
        }
    
        @Autowired
        private void setApplicationContext(ApplicationContext applicationContext) {
            BeanProvider.applicationContext = applicationContext;
        }
    }
    

    顶级 SwingApp 类:

    @SpringBootApplication
    public class SwingApp implements CommandLineRunner {
    
        public static void main(String[] args) {
            new SpringApplicationBuilder(SwingApp.class)
                    .headless(false).bannerMode(Banner.Mode.OFF).run(args);
        }
    
        @Override
        public void run(String... args) throws Exception {
            SwingUtilities.invokeLater(() -> {
                MainFrame frame = new MainFrame();
                frame.setVisible(true);
            });
        }
    }
    

    MainFrame 类:

    public class MainFrame extends javax.swing.JFrame {
        public MainFrame() {
            initComponents();
        }
        private void initComponents() {
            //Gui Builder generated code. Bean not managed by spring. 
            //Thus, autowired inside CustomPanel won't work if you rely on ComponentScan. 
            jPanel1 = new CustomJPanel();         
            //...
        }
        private CustomJPanel jPanel1;
    }
    

    您要自动装配的面板类:

    //@Component //not needed since it wont work with gui generated code.
    public class CustomJPanel extends javax.swing.JPanel{
        @Autowired
        private SomeRepository someRepository
        public CustomJPanel(){
            BeanProvider.autowire(this); //use someRepository somewhere after this line.
        }
    }
    

    【讨论】:

      【解决方案3】:

      我在 JavaFx 项目中遇到了同样的问题。服务和组件注释类在 UI 控制器中为空,即使它显示在创建它的上下文中。下面的代码对我有用

      @Component
      public class FxmlLoaderWithContext {
      private final ApplicationContext context;
      
      @Autowired
      public FxmlLoaderWithContext(ApplicationContext context) {
          this.context = context;
          FXMLLoader fxmlloader = new FXMLLoader();
          fxmlloader.setControllerFactory(context::getBean); //this row ensure services and components to be autowired
      }
      

      }

      【讨论】:

        【解决方案4】:

        我认为它返回 null 是因为您使用命令 new 创建对象,例如 new InputNameForm()。当创建这样的对象时,该对象不是由 Spring 管理的。这就是自动接线不起作用的原因。 解决方案是将您的类注册为 bean。 您可以使用here 中的类。

        @Component
        public class BeanProvider {
        private static ApplicationContext applicationContext;
            
            public static void autowire(Object object) {
                applicationContext.getAutowireCapableBeanFactory().autowireBean(object);
            }
            
            @Autowired
            private void setApplicationContext(ApplicationContext applicationContext) {
                BeanProvider.applicationContext = applicationContext;
            }
        }
        

        然后,在您的类 InputNameForm 构造函数中,调用它:

        class InputNameForm() {
        BeanProvider.autowire(this);
        ...
        }
        

        就是这样。春天会处理剩下的。

        【讨论】:

          猜你喜欢
          • 2018-07-28
          • 1970-01-01
          • 2016-01-09
          • 1970-01-01
          • 1970-01-01
          • 2017-05-22
          • 2015-05-02
          • 1970-01-01
          • 2018-03-15
          相关资源
          最近更新 更多