web-dev-qa-db-fra.com

Spring boot câblage automatique d'une interface avec plusieurs implémentations

Dans Spring normal, lorsque nous voulons câbler automatiquement une interface, nous définissons son implémentation dans le fichier de contexte Spring. Et Spring Boot? Comment pouvons-nous y parvenir? actuellement, nous n'autorisons que les classes qui ne sont pas des interfaces. Une autre partie de cette question concerne l'utilisation d'une classe dans une classe Junit à l'intérieur d'un projet de démarrage Spring. Si nous voulons utiliser un CalendarUtil par exemple, si nous câblons automatiquement CalendarUtil, il lèvera une exception de pointeur nul. Que pouvons-nous faire dans ce cas? Je viens d'initialiser en utilisant "nouveau" pour l'instant ...

8
user666

Utilisation @Qualifier l'annotation est utilisée pour différencier les beans de la même interface
Jetez un œil à Spring Boot documentation
De plus, pour injecter tous les beans de la même interface, juste autowire List de l'interface
(De la même manière dans Spring/Spring Boot/SpringBootTest)
Exemple ci-dessous:

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

}

}

Pour la deuxième partie de votre question, regardez ces réponses utiles premier / second

16
tsarenkotxt

Vous pouvez également le faire fonctionner en lui donnant le nom de l'implémentation.

Par exemple:

@Autowired
MyService firstService;

@Autowired
MyService secondService;
9
Raj Shah

Comme mentionné dans les commentaires, en utilisant le @Qualifier annotation, vous pouvez distinguer différentes implémentations comme décrit dans docs .

Pour les tests, vous pouvez également faire de même. Par exemple:

    @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....
    }
}
2
Urosh T.