web-dev-qa-db-fra.com

Spring pouvez-vous vous connecter à une classe abstraite?

Le printemps ne parvient pas à autoriser automatiquement mon objet? Est-il possible d'autowire un objet dans une classe abstraite. Supposons que tous les schémas sont fournis dans application-context.xml

Question: Quelle annotation doit figurer sur la base et sur les classes d'extension (le cas échéant) @Service @Component?

Exemple

abstract class SuperMan {

    @Autowire
    private DatabaseService databaseService;

    abstract void Fly();

    protected void doSuperPowerAction(Thing thing) {

        //busy code

        databaseService.save(thing);

    }
}

Classe d'extension

public class SuperGirl extends SuperMan {

    @Override
    public void Fly() {
        //busy code
    }

    public doSomethingSuperGirlDoes() {

        //busy code

        doSuperPowerAction(thing)

    }

application-context.xml

<context:component-scan base-package="com.baseLocation" />
<context:annotation-config/>
45
stackoverflow

Normalement, Spring devrait effectuer le câblage automatique, tant que votre classe abstraite se trouve dans le package de base fourni pour l'analyse des composants. 

Voir this et this pour une référence ultérieure.

@Service et @Component sont deux stéréotypes qui créent des beans du type annoté dans le conteneur Spring. En tant que document Spring Docs, 

Cette annotation sert de spécialisation de @Component, permettant à les classes d'implémentation à détecter automatiquement via l'analyse de chemin d'accès aux classes.

25
Andrei Nicusan

J'ai ce genre de configuration de printemps de travail

une classe abstraite avec un champ auto-câblé

public abstract class AbstractJobRoute extends RouteBuilder {

    @Autowired
    private GlobalSettingsService settingsService;

et plusieurs enfants définis avec l'annotation @Component.

31
Frederic Close

Dans mon cas, dans une application Spring4, je devais utiliser un motif abstrait d'usine classique (pour lequel j'ai pris l'idée de - http://Java-design-patterns.com/patterns/abstract-factory/ ) pour créer des instances à chaque fois qu’une opération devait être effectuée. Mon code devait donc être conçu de la manière suivante:

public abstract class EO {
    @Autowired
    protected SmsNotificationService smsNotificationService;
    @Autowired
    protected SendEmailService sendEmailService;
    ...
    protected abstract void executeOperation(GenericMessage gMessage);
}

public final class OperationsExecutor {
    public enum OperationsType {
        ENROLL, CAMPAIGN
    }

    private OperationsExecutor() {
    }

    public static Object delegateOperation(OperationsType type, Object obj) 
    {
        switch(type) {
            case ENROLL:
                if (obj == null) {
                    return new EnrollOperation();
                }
                return EnrollOperation.validateRequestParams(obj);
            case CAMPAIGN:
                if (obj == null) {
                    return new CampaignOperation();
                }
                return CampaignOperation.validateRequestParams(obj);
            default:
                throw new IllegalArgumentException("OperationsType not supported.");
        }
    }
}

@Configurable(dependencyCheck = true)
public class CampaignOperation extends EO {
    @Override
    public void executeOperation(GenericMessage genericMessage) {
        LOGGER.info("This is CAMPAIGN Operation: " + genericMessage);
    }
}

Initialement pour injecter les dépendances dans la classe abstraite, j’ai essayé toutes les annotations de stéréotypes comme @Component, @Service, etc. mais même si le fichier de contexte Spring avait ComponentScanning pour l’ensemble du paquet, Ayant nul pour ses propriétés car Spring était incapable de reconnaître et d'injecter ses dépendances. Après de nombreux essais et erreurs, j'ai utilisé cette annotation **@Configurable(dependencyCheck = true)** et enfin Spring a pu injecter les dépendances et j'ai pu utiliser les propriétés de la sous-classe sans les encombrer trop de propriétés.

<context:annotation-config />
<context:component-scan base-package="com.xyz" />

J'ai aussi essayé ces autres références pour trouver une solution:

  1. http://www.captaindebug.com/2011/06/implementing-springs-factorybean.html#.WqF5pJPwaAN
  2. http://forum.spring.io/forum/spring-projects/container/46815-problem-with-autowired-in-abstract-class
  3. https://github.com/cavallefano/Abstract-Factory-Pattern-Spring-Annotation
  4. http://www.jcombat.com/spring/factory-implementation-using-servicelocatorfactorybean-in-spring
  5. https://www.madbit.org/blog/programming/1074/1074/#sthash.XEJXdIR5.dpbs
  6. Utilisation de la fabrique abstraite avec le cadre Spring
  7. Printemps Autowiring ne fonctionne pas pour les classes abstraites
  8. Injecter la dépendance de ressort en super classe abstraite
  9. Classe Spring et classe abstraite - propriétés d'injection dans des classes abstraites
    1. Dépendance de l'autowire Spring définie dans une classe abstraite

S'il vous plaît essayez d'utiliser **@Configurable(dependencyCheck = true)** et mettre à jour ce post, je pourrais essayer de vous aider si vous rencontrez des problèmes.

1
user1295235

Et si vous avez besoin d’une opération de base de données dans SuperGirl, vous l’injecterez à nouveau dans SuperGirl.

Je pense que l'idée principale est d'utiliser la même référence d'objet dans différentes classes. Alors qu'en est-il de ceci:

//There is no annotation about Spring in the abstract part.
abstract class SuperMan {


    private final DatabaseService databaseService;

    public SuperMan(DatabaseService databaseService) {
     this.databaseService = databaseService;
    }

    abstract void Fly();

    protected void doSuperPowerAction(Thing thing) {

        //busy code

        databaseService.save(thing);

    }
}

@Component
public class SuperGirl extends SuperMan {

private final DatabaseService databaseService;

@Autowired
public SuperGirl (DatabaseService databaseService) {
     super(databaseService);
     this.databaseService = databaseService;
    }

@Override
public void Fly() {
    //busy code
}

public doSomethingSuperGirlDoes() {

    //busy code

    doSuperPowerAction(thing)

}

A mon avis, injecter une fois courir partout :)

0
Muhammed Ozdogan