3
votes

Spring Boot: comment injecter deux classes ayant le même nom

Dans mon application, j'ai deux classes ayant le même nom, mais bien sûr dans des packages différents.

Les deux classes doivent être injectées dans l'application; Malheureusement, je reçois le message d'erreur suivant:

package org.pmesmeur.springboot.training.service.feature2;

import org.springframework.stereotype.Component;


@Component
public class MyFeature implements IMyFeature {

    @Override
    public void print() {
        System.out.print("FooBar");
    }

}

Mon problème peut être reproduit par l'exemple suivant:

package org.pmesmeur.springboot.training.service.feature2;

public interface IMyFeature {

    void print();

}

XXX


package org.pmesmeur.springboot.training.service.feature1;

import org.springframework.stereotype.Component;

@Component
public class MyFeature implements IMyFeature {

    @Override
    public void print() {
        System.out.print("HelloWorld");
    }

}

package org.pmesmeur.springboot.training.service.feature1;

public interface IMyFeature {

    void print();

}

@Component
@EnableConfigurationProperties(ServiceProperties.class)
public class MyService implements IService {

    private final ServiceProperties serviceProperties;
    private final IProvider provider;
    private final org.pmesmeur.springboot.training.service.feature1.IMyFeature f1;
    private final org.pmesmeur.springboot.training.service.feature2.IMyFeature f2;


    @Autowired
    public MyService(ServiceProperties serviceProperties,
                     IProvider provider,
                     org.pmesmeur.springboot.training.service.feature1.IMyFeature f1,
                     org.pmesmeur.springboot.training.service.feature2.IMyFeature f2) {
        this.serviceProperties = serviceProperties;
        this.provider = provider;
        this.f1 = f1;
        this.f2 = f2;
    }
    ...

Si j'utilise des noms différents pour mon classes MyFeature , mon problème disparaît !!!

J'ai l'habitude de travailler avec Guice et ce framework n'a pas ce genre de problème / limitation

Il semble que le framework d'injection de dépendances Spring n'utilise que le nom-classe au lieu de nom-package + nom-classe afin de sélectionnez ses classes.

Dans la «vraie vie», j'ai ce problème avec un projet beaucoup plus grand et je préférerais fortement ne pas avoir à renommer mes classes: quelqu'un peut-il m'aider?

Un dernier point, je préférerais éviter les "trucs" comme l'utilisation @Qualifier (value = "ABC") lors de l'injection de mes classes: dans mon échantillon, il ne devrait y avoir aucune ambiguïté pour trouver l'instance correcte de MyFeature car ils n'implémentent pas la même interface


3 commentaires

lorsque les deux interfaces de différents packages ont les mêmes méthodes abstraites, pourquoi ne pouvez-vous pas utiliser une seule interface?


Utilisez-vous l'annotation @Bean n'importe où dans votre projet?


Pouvez-vous donner un commentaire sur ma réponse? J'aimerais aider à finaliser ce numéro !!


4 Réponses :


0
votes

Vous pouvez attribuer une valeur à chaque composant, par exemple @Component (value = "someBean") puis injectez-le avec @Qualifier par exemple

@Autowired
public SomeService(@Qualifier("someBean") Some s){
   //....
}


0 commentaires

0
votes

Vous pouvez faire quelque chose comme ceci;

dans le package a

@Configuration
public class Configuration {

    @Bean
    public a.MyFeature f1() {
        return new a.MyFeature();
    }

    @Bean
    public b.MyFeature f2() {
        return new b.MyFeature();
    }
}

dans le package b p>

public class MyFeature implements IMyFeature {

    @Override
    public void print() {
        System.out.print("HelloWorld");
    }
}

et dans certaines config class ;

public class MyFeature implements IMyFeature {

    @Override
    public void print() {
        System.out.print("FooBar");
    }
}

Ensuite, vous pouvez les connecter automatiquement avec les noms f1 et f2 , qui sont les noms de leurs méthodes de constructeur de bean respectives.

Vous pouvez faire la même chose avec @Component ("f1") & @Component("f2")


Même si différentes interfaces sont implémentées et sont dans des packages différents, un nom de bean identique cause ce problème, et vous devez utiliser une sorte de dénomination personnalisée pour distinguer. Utilisation de la logique Spring personnalisée serait bien trop moche par rapport à ce que vous feriez avec les solutions ci-dessus.


0 commentaires

0
votes

Spring fournit un câblage automatique par type et par nom. Votre nom de classe est le même. Par défaut, Spring considère uniquement le nom de classe et non le package. Mais vous pouvez remplacer ce comportement en définissant une implémentation personnalisée de l'interface BeanNameGenerator dans laquelle vous pouvez générer un nom en utilisant à la fois le package et le nom. Je ne propose pas de solution de code car je pense que vous devriez en savoir plus à ce sujet.


0 commentaires

1
votes

La simple réimplémentation de BeanNameGenerator ajoute un nouveau problème pour les beans déclarés / instanciés par des noms

static class BeanNameGeneratorIncludingPackageName extends AnnotationBeanNameGenerator {

    public BeanNameGeneratorIncludingPackageName() {
    }

    @Override
    public String buildDefaultBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
        return beanDefinition.getBeanClassName();
    }

}

J'ai résolu ce problème en étendant AnnotationBeanNameGenerator code > et redéfinition de la méthode buildDefaultBeanName ()

@Component("HelloWorld")
class MyComponent implements IComponent {
...
}

@Qualifier(value = "HelloWorld") IComponent component


0 commentaires