PowerFlower
PowerFlower

Reputation: 1619

CommandLineRunner and Beans (Spring)

code what my question is about:

   @SpringBootApplication
public class Application {

    private static final Logger log = LoggerFactory.getLogger(Application.class);

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

    @Bean
    public Object test(RestTemplate restTemplate) {
        Quote quote = restTemplate.getForObject(
                "http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
        log.info(quote.toString());
        return new Random();
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }

    @Bean
    public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
        return args -> {
            Quote quote = restTemplate.getForObject(
                    "http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
            log.info(quote.toString());
        };
    }
}

I'm very new to Spring. As far as I understood the @Bean annotation is responsible that an Object is saved in a IoC container, correct?

If so: Are first all Methods with @Bean collected and then executed?

In my example I added a method test() what does the same as run() but returns an Object (Random()) instead. The result is the same so it is working with CommandLineRunner and Object.

Is there a Reason why it should return a CommandLineRunner i.e. use the syntax like run()?

Moreover: At that point I don't see so far the advantage to move methods to an container. Why not just execute it?

Thank you!

Upvotes: 8

Views: 15211

Answers (1)

Evgeni Dimitrov
Evgeni Dimitrov

Reputation: 22506

@Configuration classes (@SpringBootApplication extends @Configuration) are the place where the spring beans are registered. @Bean is used to declare a spring bean. The method that is annotated with @Bean has to return an object(the bean). By default the spring beans are singletons, so once the method annotated with @Bean is executed and returns it's value this object lives til the end of the application.

In your case

    @Bean
    public Object test(RestTemplate restTemplate) {
        Quote quote = restTemplate.getForObject(
                "http://gturnquist-quoters.cfapps.io/api/random", Quote.class);
        log.info(quote.toString());
        return new Random();
    }

this will produce s singleton bean of type Random with name 'test'. So if you try to inject (e.g. with @Autowire) a bean of that type or name in other spring bean you will get that value. So this is not a good use of @Bean annotation, unless you want exactly that.

CommandLineRunner on the other hand is a special bean that lets you execute some logic after the application context is loaded and started. So it makes sense to use the restTemplate here, call the url and print the returned value.

Not long ago the only way to register a Spring bean was with xml. So we had an xml files and bean declarations like this:

<bean id="myBean" class="org.company.MyClass">
  <property name="someField" value="1"/>
</bean>

The @Configuration classes are the equivalent of the xml files and the @Bean methods are the equivalent of the <bean> xml element.

So it's best to avoid executing logic in bean methods and stick to creating objects and setting their properties.

Upvotes: 14

Related Questions