Восстановление бобов в Spring Boot? - PullRequest
0 голосов
/ 20 февраля 2020

В прошлом я работал с Legacy Spring. Мы определили наши bean-компоненты с помощью конфигурации xml и связали их вручную. Моя команда наконец-то предпринимает согласованные усилия, чтобы обновить аннотации и использовать Spring Boot вместо «традиционного» подхода с Spring MVC.

С учетом сказанного я не могу понять, как, черт возьми, я получаю бин в Boot. В устаревшем случае Spring либо использовал бы инъекцию конструктора / сеттера (в зависимости от нашей конфигурации), либо мы могли бы напрямую вызывать bean-компонент с помощью context.getBean("myBeanID"); Однако, похоже, это больше не так.

Я собрал вместе небольшой тестовый пример, чтобы попытаться заставить это работать в следующем коде:

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

}

Я попытался автоматически связать объект ApplicationContext с классом TennisCoach. Когда я запускаю это, этот объект имеет значение null.

Как мы получаем бины в Boot?

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Наиболее распространенным подходом является использование аннотации @Autowired. Кроме того, поскольку у вас есть две разные реализации интерфейса Coach, вы должны использовать аннотацию @Qualifier, чтобы сообщить Spring, какую реализацию интерфейса следует внедрить.

Некоторые руководства по этим двум аннотациям, чтобы начать работу:

Например, для добавления бобов в вашем контроллере, вы должны сделать:

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

}

Или, чтобы вставить soccerCoach в tennisCoach, как вы и предполагали, используя инжектор конструктора, код будет выглядеть так:

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

}

Если вам действительно нужно использовать ApplicationContext для извлечения какого-либо компонента, не рекомендуется делать это в вашем классе, который имеет функцию main. Просто создайте другой компонент (вы можете использовать аннотацию @Componenent). Вот пример:

@Component
public class AnyComponent {

    @Autowired
    private ApplicationContext applicationContext;

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

}

И внедрить этот bean-компонент в поток приложений, который может находиться в контроллере, службе или репозитории:

@RestController
class MyController {

    @Autowired
    private AnyComponent anyComponent;

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

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

}

Примечание. Инъекция bean-компонентов с помощью аннотаций - это нечто специфицирует c для Spring, в общем, не для Spring Boot в частности.

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

Начиная с Spring 2.5, введена платформа новый стиль внедрения зависимостей, управляемый аннотациями @Autowired. Эта аннотация позволяет Spring разрешать и вводить взаимодействующие bean-компоненты в ваш bean-компонент.

1 голос
/ 20 февраля 2020

Введите необходимые бобы напрямую. Нет необходимости ApplicationContext в загрузке Spring.

@Service
class TennisCoach {

    private SoccerCoach soccerCoach;

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

}
...