В обычном Spring, когда мы хотим автоматически подключить интерфейс, мы определяем его реализацию в файле контекста Spring.
в настоящее время мы только классы autowire, которые не являются интерфейсами.
Другая часть этого вопроса касается использования класса в классе Junit внутри проекта загрузки Spring.
Если мы хотим использовать CalendarUtil, например, если мы автоматически подключаем CalendarUtil, он выдаст исключение с нулевым указателем. Что делать в этом случае? Я только что инициализировал, используя «новый» ...
Например, если у нас есть интерфейс под названием ChargeInterface, и у него есть две реализации: ChargeInDollars и ChrageInEuro, и у вас есть другой класс, содержащий определенную бизнес-логику под названием AmericanStoreManager, который должен использовать реализацию ChargeInDollars ChargeInterface. Вы определяете автоматически подключенный ChargeInterface, но как вы решаете, какую реализацию использовать?
Использование квалификаторов точно так же, как и в Spring, потому что Spring-boot - это Spring. Итак, прочтите документацию Spring и найдите «Qualifier». Или, поскольку вам все равно нужна конкретная реализация, вы можете просто автоматически подключить класс, а не интерфейс.
Как упоминалось в комментариях, используя аннотацию @Qualifier, вы можете различать различные реализации, как описано в документы.
Для тестирования можно использовать тоже самое. Например:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyClassTests {
@Autowired
private MyClass testClass;
@MockBean
@Qualifier("default")
private MyImplementation defaultImpl;
@Test
public void givenMultipleImpl_whenAutowiring_thenReturnDefaultImpl() {
// your test here....
}
}
Используйте аннотацию @Qualifier, чтобы различать компоненты с одним и тем же интерфейсом.
Взгляните на Spring Boot документация
Кроме того, чтобы внедрить все компоненты одного и того же интерфейса, просто автопроводList интерфейса
(То же самое в Spring / Spring Boot / SpringBootTest)
Пример ниже:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
public interface MyService {
void doWork();
}
@Service
@Qualifier("firstService")
public static class FirstServiceImpl implements MyService {
@Override
public void doWork() {
System.out.println("firstService work");
}
}
@Service
@Qualifier("secondService")
public static class SecondServiceImpl implements MyService {
@Override
public void doWork() {
System.out.println("secondService work");
}
}
@Component
public static class FirstManager {
private final MyService myService;
@Autowired // inject FirstServiceImpl
public FirstManager(@Qualifier("firstService") MyService myService) {
this.myService = myService;
}
@PostConstruct
public void startWork() {
System.out.println("firstManager start work");
myService.doWork();
}
}
@Component
public static class SecondManager {
private final List<MyService> myServices;
@Autowired // inject MyService all implementations
public SecondManager(List<MyService> myServices) {
this.myServices = myServices;
}
@PostConstruct
public void startWork() {
System.out.println("secondManager start work");
myServices.forEach(MyService::doWork);
}
}
}
Что касается второй части вашего вопроса, посмотрите эти полезные ответы первый / второй
Для модульного теста я использовал следующие аннотации: @SpringBootTest (classes = CalendarUtil.class) @RunWith (SpringRunner.class), а затем я автоматически подключил класс.
У вас больше нет проблем с @Autowired ?
да, когда мы добавляем тест весенней загрузки и запускаем с аннотациями, мы можем успешно использовать аннотацию с автоматическим подключением
Всякий раз, когда я использую вышеуказанное в Junit вместе с Mocking, автоматическое подключение снова выходило из строя. Есть какие-нибудь советы по этому поводу? Проблема в том, что я не хочу издеваться над всеми классами, я хочу, чтобы некоторые из них были издевательскими, а другие - автоматическими. Как я могу этого добиться?
Мне удалось сделать это с помощью @Spy вместо Autowired в качестве аннотации в Junit и самостоятельно инициализировать класс без использования аннотаций запуска Spring.
попробуйте SpyBean, а также с @RunWith(SpringRunner.class), посмотрите этот пример - shekhargulati.com/2017/07/20/using-spring-boot-spybean
Когда я попытался внедрить две реализации в один компонент в разные поля, это не помогло. Внедрение с именем реализации помогло.
@ S.Dayneko не могли бы вы предоставить пример кода / версию Spring? Вы используете @Qualifier("implOne") и @Qualifier("implTwo"), также он может быть квалифицирован по имени файла без аннотации @Qualifier
См. Ответ Радж Шаха ниже. Он также работает с конструктором (и без @Autowired с весны 4.3)
правильно, как я писал выше - ... it can be qualified by filed name ...
Вы также можете заставить его работать, дав ему имя реализации.
Например:
@Autowired
MyService firstService;
@Autowired
MyService secondService;
Это важно!
Этот подход сработал для меня, используя Qualifier вместе с аннотацией Autowired. Я тоже видел то же самое в документации docs.spring.io/spring/docs/4.3.12.RELEASE/…. Приведите пример, работает ли это для вас, как указано выше. Спасибо.
Это было лучше
Это было хорошо, но действительно ли это инъекция зависимостей? Поскольку мы связываем переменную с именем самой службы.
Так же, как в Spring (подсказка: Spring Boot на самом деле является Spring): вы определяете bean-компонент либо с помощью аннотации, либо с помощью метода, аннотированного Bean, как описано в документации Spring, и вы автоматически подключаете интерфейс, который реализует этот bean-компонент. . Если бы вы показали код, а не расплывчато его описали, все было бы проще.