简体   繁体   中英

How to configure spring-boot with swing application

I'd like using spring-boot-starter-data-jpa features to create a non-web aplication. In the 52.4 documentation says:

Application code that you want to run as your business logic can be implemented as a CommandLineRunner and dropped into the context as a @Bean definition.

My AppPrincipalFrame looks like:

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

And boot application class looks like:

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

But does not work. Anybody have a sample about this?

Edited and exception added.

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 

Regards.

It's been a while since you posted the question, but I run out with the same problem in a old project that I'm migrating and figured a different way, I think that more clear, to make the things work.

Instead of using SpringApplication.run(Application.class, args); you can use: new SpringApplicationBuilder(Main.class).headless(false).run(args); and it isn't necessary to make toy Application class extends from JFrame. Therefore the code could look like:

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

The Swing application must be placed on the Swing Event Queue. Not doing so is a serious mistake.

So the correct way to do it:

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

In addition, we can just use the @SpringBootApplication annotation.

@SpringBootApplication
public class SwingApp extends JFrame {

See my Spring Boot Swing integration tutorial for a full working example.

Another simple and elegant solution is to disable headless property as shown here. You will have to do it though, right before you create/show the JFrame.

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

So, the thing that worked for me:

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

Annotations in MyClass.class (I am not aware if they play any role):

@SpringBootApplication
@EnableWebMvc

I have found the solution very simple (spring server run first, swing run later)

//@Component
public class SwingApp extends JFrame {
vv...
}

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class)
                .headless(false).run(args);

        SwingApp sw = new SwingApp();
        sw.setVisible(true);    
    }
}

swing run first, call spring server run later

//@Component
public class SwingApp extends JFrame {
    
    vv...

    private void jButtonRunSpringServer(java.awt.event.ActionEvent evt){
        String [] args = {"abc","xyz"};
        Application.runSpringServer(args);
    }
}


@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SwingApp sw = new SwingApp();
        sw.setVisible(true);
    }

    public static void runSpringServer(String[] args) {
        /*
        ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class)
                .headless(false).run(args);
        */
        SpringApplication.run(Application.class, args);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM