Как настроить spring -boot с помощью swing-приложения

Я хотел бы использовать функции spring -boot-starter-data-jpa для создания не-веб-приложения. В документации 52.4 говорится:

Код приложения, который вы хотите запустить в качестве бизнес-логики, может быть реализованный как CommandLineRunner и попавший в контекст как @ Bean.

Мой AppPrincipalFrame выглядит следующим образом:

@Component
public class AppPrincipalFrame extends JFrame implements CommandLineRunner{

private JPanel contentPane;

@Override
public void run(String... arg0) throws Exception {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                AppPrincipalFrame frame = new AppPrincipalFrame();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

И класс загрузочного приложения выглядит следующим образом:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {  
  public static void main(String[] args) {
   ApplicationContext context = SpringApplication.run(Application.class, args);
   AppPrincipalFrame appFrame = context.getBean(AppPrincipalFrame.class);
  }
}

Но не работает. У кого-нибудь есть пример об этом?

Отредактировано и добавлено исключение.

Exception in thread "main" org.springframework.beans.factory.BeanCreationException:      Error creating bean with name 'appPrincipalFrame'.

Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [es.adama.swing.ui.AppPrincipalFrame]: Constructor threw exception; nested exception is java.awt.HeadlessException 

С уважением.

Ответы

Ответ 1

Прошло некоторое время с тех пор, как вы разместили этот вопрос, но я столкнулся с той же проблемой в старом проекте, который я переношу, и решил по-другому, я думаю, что это более понятно, чтобы все было в порядке.

Вместо использования SpringApplication.run(Application.class, args); вы можете использовать: new SpringApplicationBuilder(Main.class).headless(false).run(args);, и нет необходимости создавать класс приложений для приложений, начиная с JFrame. Поэтому код может выглядеть так:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {  
    public static void main(String[] args) {
    ConfigurableApplicationContext context = new SpringApplicationBuilder(Application.class).headless(false).run(args);
    AppPrincipalFrame appFrame = context.getBean(AppPrincipalFrame.class);
}

Ответ 2

Приложение Swing должно быть помещено в очередь событий Swing. Не делать это серьезная ошибка.

Итак, правильный способ сделать это:

public static void main(String[] args) {

    ConfigurableApplicationContext ctx = new SpringApplicationBuilder(SwingApp.class)
            .headless(false).run(args);

    EventQueue.invokeLater(() -> {
        SwingApp ex = ctx.getBean(SwingApp.class);
        ex.setVisible(true);
    });
}

Кроме того, мы можем просто использовать аннотацию @SpringBootApplication.

@SpringBootApplication
public class SwingApp extends JFrame {

Смотрите мой учебник по интеграции Spring Boot Swing для полного рабочего примера.

Ответ 3

Другое простое и элегантное решение - отключить свойство без заголовка, как показано здесь. Вы должны будете сделать это, прямо перед тем, как создавать/показывать JFrame.

System.setProperty("java.awt.headless", "false"); //Disables headless

Итак, вещь, которая работала для меня:

SpringApplication.run(MyClass.class, args);
System.setProperty("java.awt.headless", "false");
SwingUtilities.invokeLater(() -> {
    JFrame f = new JFrame("myframe");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
});

Аннотации в MyClass.class (я не знаю, играют ли они какую-либо роль):

@SpringBootApplication
@EnableWebMvc