Spring boot - How to create spring beans for the objects created in static methods

1.8k Views Asked by At

I am trying to move old project to spring boot project. I created the spring project project and moved the code and now I am trying to springify the project by creating beans for the objects.

@SpringBootApplication
public class TestApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

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

        final CommandLineArgs arguments = new CommandLineArgs();
        CmdLineParser parser = new CmdLineParser(arguments);
        parser.parseArgument(args);
        A.generatedData(arguments);
    }
}

class A{
    public static void generatedData(CommandLineArgs arguments) {
        LOG.info("Starting visualization.");

        B b = new B(createModel(arguments));
        b.build();
    }
    
    private static Model createModel(CommandLineArgs arguments) {
        ...
    }
}

class B{
    public void build() {
        ...
    }
}

Some objects are created within the static method so I am not sure how to create beans of those objects. Can you please help convert this code in the spring world?

1

There are 1 best solutions below

2
H3AR7B3A7 On

Original answer:

You typically just make a config class containing beans that return the object you want to wire in anywhere:

@Configuration
public class MyConfiguration {
  @Bean
  public B b() {
    return new B();
  }
}

And then you can wire them in like this:

@Component
@RequiredArgsConstructor
public class MyRunner implements CommandLineRunner {

    private final B b; 

    @Override
    public void run(String... args) throws Exception {
        b.build();
    }
}

Also, by implementing the CommandLineRunner or ApplicationRunner interfaces on a component, you can leave your application class alone...

These will run after the context is loaded and before your application starts.

You can also create beans with the @Component annotation:

@Component
public class B {
  // ...
}

Or even create beans depending on other beans. Here's a slightly more complex example:

@Configuration
public class DependentBeanConfig {

    @Bean
    SimpleBean someBean() { // interface
        return new SomeBeanImpl(); // implementation
    }
    
    @Bean
    DependentBean dependentBean(){
        return new DependentBeanImpl(simpleBean());
    }
}

@Configuration and @Service are just sub-types of the @Component annotation that basically do exactly the same. You can even create static beans inside them...

All of Spring is built upon this concept.

But you do not autowire static members, because that would be rather contradictory. If it belongs to the class it should not be wired in or vice versa. If you want to wire it in, it probably does not belong.

Another problem you might run in to is non-object oriented programming, where you might want to rethink the objects in the code.

Addendum:

To configure the bean create some setters:

public class B {
  private YourProperty yourProperty;

  //...
  public setYourProperty(YourProperty yourProperty) {
    this.yourProperty = yourProperty;
  }
}

And in the bean creation:

@Configuration
public class MyConfiguration {
  @Bean
  public B b() {
    B b = new B();
    b.setYourProperty(yourProperty)
    return b;
  }
}

You can also wire in an Environment bean. Then you can fetch properties from the environment:

@Configuration
// You don't need this annotation for application.properties in Spring Boot projects
// I added it to easily understand what is going on
@PropertySource("classpath:yourpropertiesfile.properties") 
public class MyConfiguration {

    private Environment environment;
    
    // ...
    @Bean
    public B b() {
        B b = new B();
        b.setYourProperty(environment.getProperty("yourProperty"))
        return b;
    }
}

You can then override these properties with commandline arguments as explained here.

The commandline / applciation runner I showed earlier can also take the application arguments without overriding environment variables.