自动装配不在springboot应用程序中工作

时间:2018-03-10 14:25:18

标签: spring swing spring-boot jframe

我正在尝试使用JFrame创建一个Spring启动应用程序。我可以在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));
  }
}

4 个答案:

答案 0 :(得分:1)

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

  1. 首先,BeanDefinitionReader从XML,注释(@Component@Service等),JavaConfig或Groovy脚本中读取有关bean的元数据。
  2. 有几个BeanPostProcessor,负责阅读您正在撰写的所有这些Spring注释(@Autowired等)。
  3. BeanFactory创建所有BeanPostProcessor,然后创建所有bean。
  4. 如果通过@Autowired运算符创建具有new依赖项的bean,会发生什么?没什么,因为它实际上并不是一个豆子。您创建的对象与IoC容器无关。如果你用@Component标记它,你可能已经在你的ApplicationContext中有了bean,但是通过new运算符创建的对象不会被Spring处理(注释不会被工作) )。

    希望这有帮助。

    PS:简化了生命周期。

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

我在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
}

}

答案 3 :(得分:0)

我认为它返回 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);
...
}

就是这样。 Spring 会处理剩下的事情。