Matthew
Matthew

Reputation: 867

Retrieving beans in Spring Boot?

I've worked with legacy Spring in the past. We defined our beans via xml configuration and manually wired them. My team is finally making a concerted effort to update to annotations and use Spring Boot instead of the 'traditional' approach with Spring MVC.

With that said, I cannot figure out how the heck I retrieve a bean in Boot. In legacy, Spring would either use constructor/setter injection (depending on our configuration), or we could directly call a bean with context.getBean("myBeanID"); However, it does not appear to be the case anymore.

I put together a small test case to try and get this working in the below code:

package com.ots;


import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class GriefUIApplication{

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

        SessionFactory factory = new Configuration().configure("hibernate.cfg.xml")
                .addAnnotatedClass(GriefRecord.class).addAnnotatedClass(RecordId.class)
                .addAnnotatedClass(CrossReferenceRecord.class)
                .buildSessionFactory();

        Statics.setSessionFactory(factory);

        TennisCoach tCoach = new TennisCoach();
        tCoach.getCoach();

    }

}



interface Coach{
    public String workout();
}


@Service
class TennisCoach implements Coach{

    private Coach soccerCoach;
    @Autowired
    private ApplicationContext context;


    public TennisCoach() {

    }

    public Coach getCoach() {

        System.out.println(context + " IS THE VALUE OF THE CONTEXT OBJECT");

        soccerCoach = (SoccerCoach)context.getBean("soccerCoach");

        System.out.println(soccerCoach.getClass());

        return soccerCoach;

    }

    @Override
    public String workout() {
        String practice = "practice your backhand!";
        System.out.println(practice);
        return practice;
    }


}

@Service
class SoccerCoach implements Coach{

    public SoccerCoach() {

    }

    @Override
    public String workout() {
        String practice = "practice your footwork!";
        System.out.println(practice);
        return practice;
    }

}

@RestController
class MyController{

    @GetMapping("/")
    public String sayHello() {

        return "Time on server is: " + new java.util.Date();
    }

}

I tried autowiring the ApplicationContext object into the TennisCoach class. When I run this, that object is null.

How do we retrieve beans in Boot?

Upvotes: 0

Views: 8835

Answers (2)

Alexandru Somai
Alexandru Somai

Reputation: 1405

The most common approach is to use the @Autowired annotation. Also, because you have two different implementations of the Coach interface, you should use the @Qualifier annotation to tell Spring which interface implementation to inject.

Some tutorials about these two annotations, to get you started:

For your example, to inject the beans into your controller, you should do:

@RestController
class MyController {

    @Autowired
    @Qualifier("soccerCoach")
    private Coach coach;

    @GetMapping("/")
    public String sayHello() {
        // this should invoke the workout() from SoccerCoach implementation
        System.out.println(coach.workout());

        return "Time on server is: " + new java.util.Date();
    }

}

Or, to inject the soccerCoach into the tennisCoach as you intended, using constructor injection , the code would become:

@Service
class TennisCoach implements Coach {

    private Coach soccerCoach;

    @Autowired
    public TennisCoach(@Qualifier("soccerCoach") Coach soccerCoach) {
        this.soccerCoach = soccerCoach;
    }

    public Coach getCoach() {
        System.out.println(soccerCoach.getClass());

        return soccerCoach;
    }

}

If you really need to use the ApplicationContext to retrieve some bean, it's not advisable to do so in your class that has the main function. Just create another bean (you could use the @Componenent annotation). Here's an example:

@Component
public class AnyComponent {

    @Autowired
    private ApplicationContext applicationContext;

    public void invokeCoach() {
        System.out.println(applicationContext.getBean("tennisCoach"));
        System.out.println(applicationContext.getBean(SoccerCoach.class));
    }

}

And inject this bean in your application flow, could be in the controller, service, or repository:

@RestController
class MyController {

    @Autowired
    private AnyComponent anyComponent;

    @GetMapping("/")
    public String sayHello() {
        anyComponent.invokeCoach();

        return "Time on server is: " + new java.util.Date();
    }

}

Note: Injecting beans through annotation is something specific to Spring, in general, not Spring Boot in particular.

From https://www.baeldung.com/spring-autowire:

Starting with Spring 2.5, the framework introduced a new style of Dependency Injection driven by @Autowired Annotations. This annotation allows Spring to resolve and inject collaborating beans into your bean.

Upvotes: 2

kann
kann

Reputation: 737

Inject the required beans directly. No need of ApplicationContext in Spring boot.

@Service
class TennisCoach {

    private SoccerCoach soccerCoach;

    @Autowired
    public TennisCoach(SoccerCoach soccerCoach) {
      this.soccerCoach = soccerCoach;
    }

}

Upvotes: 1

Related Questions