2017-03-26 13 views
0

Dies ist, was wir im Moment haben:Frühling Injektion verschiedene Service-Implementierungen

interface ReportService { 

    Report generate(); 
    } 

und Interface-Implementierung:

@Service 
public class ReportService_1Impl implements ReportService { 

    public Report generate() { 

     System.out.println("Report Service 1: generate Report."); 
     return new Report(); 
    } 
} 

Was die neuen Geschäftsanforderungen für dieses Stück Code ist:

  • Implementieren Sie neue ReportService_2, die mit der neuen Berichts-Engine kommunizieren wird, aber neuer Service noch h ave die gleiche generate() Methode mit der gleichen Signatur;
  • Implementieren Sie die Möglichkeit, in Runtime basierend auf einer vordefinierten Konfiguration zwischen diesen Diensten zu wechseln;
  • Als eine Option: denken Sie über die Fähigkeit, neue ReportServices in der nächsten Funktion einzuführen.

Okay, lassen Sie uns alle Schritte umzusetzen beginnen, die oben erwähnt wurden:

Schritt 1:

neue ReportService_2:

@Service 
@Qualifier("ReportService_2") 
public class ReportService_2Impl implements ReportService { 
    public Report generate() { 

     System.out.println("Report Service 2: generate Report."); 
     return new Report(); 
    } 
} 

@Qualifier("ReportService_1") für ReportService_1Impl hinzufügen

@Service 
@Qualifier("ReportService_1") 
public class ReportService_1Impl implements ReportService { 

    public Report generate() { 

     System.out.println("Report Service 1: generate Report."); 
     return new Report(); 
    } 
} 

Schritt 2:

Wie zwischen zwei Dienste in Runtime auf Basis von Konfiguration wechseln?

Ehrlich gesagt, ich bin nicht sicher, wie diese Aufgabe ordnungsgemäß umzusetzen, habe ich eingeführt gerade neue ReportService, die die Rolle des Containers oder Wrapper für ReportService_1Impl und ReportService2_Impl und bestimmt, spielen die Implementierungen verwenden müssen:

@Service 
public class ReportServiceImpl implements ReportService { 

    @Autowired 
    @Qualifier("ReportService_1") 
    private ReportService reportService_1; 
    @Autowired 
    @Qualifier("ReportService_2") 
    private ReportService reportService_2; 

    private ReportService getActiveReportService() { 

     return true ? reportService_1 : reportService_2; 
    } 

    public Report generate() { 

     return getActiveReportService().generate(); 
    } 
} 

Sieht ziemlich hässlich aus, aber ich glaube, dass wir damit leben können.

Und der letzte Schritt, in dem ich die folgenden Anforderungen implementieren müssen:

denken über die Fähigkeit, neue ReportService's in der nächsten Funktion einzuführen. auf jeden Fall injizieren müssen neu ReportService_N in ReportServiceImpl erstellt und es wird wie

Ich weiß nicht, wie diese richtig implementieren, da mit der aktuellen Implementierung, jedes Mal, wenn ich ReportService_N neue hinzufügen, werde ich daran erinnern müssen, dass ich aussehen :

@Service 
public class ReportServiceImpl implements ReportService { 

    @Autowired 
    @Qualifier("ReportService_1") 
    private ReportService reportService_1; 
    @Autowired 
    @Qualifier("ReportService_2") 
    private ReportService reportService_2; 
    @Autowired 
    @Qualifier("ReportService_3") 
    private ReportService reportService_3; 
    @Autowired 
    @Qualifier("ReportService_4") 
    private ReportService reportService_4; 
    @Autowired 
    @Qualifier("ReportService_N") 
    private ReportService reportService_N; 

Glauben Sie, dass diese Art von Problem einige Muster mehrere Male in der Vergangenheit gelöst wurde und bereits definiert, die ich verwenden müssen.

Kann mir jemand einen Rat oder einen Musternamen geben, der mir hilft, mein Problem mit dem letzten Szenario zu lösen?

+0

Gehen Sie für Strategie-Design-Muster –

Antwort

1

Sie verkomplizieren die Dinge sehr, eher können Sie eine Bohne dynamisch zuweisen, indem Sie @Resource(name="${reportService}") verwenden, wie unten gezeigt, d. H. Sie können den Bean-Namen (je nachdem, was Sie zur Laufzeit injizieren wollten) tatsächlich auf application.properties externalisieren.

Ich habe Controller zu autowire Ihre ReportService verwendet, aber das gleiche kann getan werden, in welcher Feder Komponente, die Sie mögen.

@Controller 
public class YourContrller { 

    @Autowired 
    @Resource(name="${reportService}") 
    private ReportService reportService; 

    public Report generate() { 

     return reportService.generate(); 
    } 
} 

@Service("ReportService_1")//name this service as ReportService_1 
public class ReportService_1Impl implements ReportService { 
    //actual code 
} 

@Service("ReportService_2")//name this service as ReportService_2 
public class ReportService_2Impl implements ReportService { 
    //actual code 
} 

Sie müssen in Ihren application.properties

Was ist mit dem Szenario einer Immobilie wie reportService=ReportService_1 Bean Namen konfigurieren, wenn Konfiguration in DB gespeichert? oder Fall, wenn wir eine Entscheidung treffen müssen, welchen Dienst basierend auf einigen eingehenden Parametern zu verwenden?

Wenn Sie wollen, dass die Eigenschaften von Datenbank konfiguriert werden, dann müssen Sie eine neue @PropertySource und sagen Feder erstellen, die Sie verwenden, dass ein einfaches Beispiel für Datenbank propertysource here gegeben zu schaffen.

Der nächste Fall ist, wenn Sie das Objekt dynamisch basierend auf einigen if passieren wollte - else Bedingungen mit einigen Variablen, dann müssen Sie dynamisch die ReportService Objekt übergeben (Polymorphismus), wie schön here erklärt.

+0

netter Ansatz! gefällt mir sehr! Aber was ist mit dem Szenario, wenn die Konfiguration in der DB gespeichert ist? oder Fall, wenn wir eine Entscheidung treffen müssen, welchen Dienst wir basierend auf einigen eingehenden Parametern verwenden sollen? bitte Beratung. – user471011

+0

Aktualisiert meine Antwort, können Sie einen Blick darauf werfen – developer

Verwandte Themen