2013-07-17 16 views
10

In base ai parametri passati a un metodo, è necessario selezionare uno dei tanti bean Spring che sono implementazioni della stessa classe, ma configurati con parametri diversi.Come selezionare l'istanza del bean Spring in fase di esecuzione

E.g. se l'utente A invoca il metodo, devo chiamare dooFoo() sul bean A, ma se è l'utente B, devo chiamare lo stesso metodo, solo sul bean B.

C'è un modo "Springier" per farlo altro che attaccare tutti i fagioli in una mappa e ricavare una chiave dai parametri passati al mio metodo?

+0

Una soluzione suggerita da un collega che era '@Autowired Map ' popolerà con ID di fagioli come la chiave - forse che potrebbe essere la soluzione meno-peggio. –

+0

Dai un'occhiata al post simile. http://stackoverflow.com/a/24525715/3796723 – linusdsunil

risposta

2

Sembra che si voglia un ServiceLocator utilizzando il contesto dell'applicazione come registro.

Vedere la classe di supporto ServiceLocatorFactoryBean per la creazione di chiavi di mapping di ServiceLocators ai nomi di bean senza l'accoppiamento del codice client a Spring.

Un'altra opzione è utilizzare una convenzione di denominazione o una configurazione basata su annotazioni.

ad esempio, supponendo di annotare Servizi con @ExampleAnnotation("someId"), è possibile utilizzare qualcosa come il seguente Localizzatore di servizio per recuperarli.

public class AnnotationServiceLocator implements ServiceLocator { 

    @Autowired 
    private ApplicationContext context; 
    private Map<String, Service> services; 

    public Service getService(String id) { 
     checkServices(); 
     return services.get(id); 
    } 

    private void checkServices() { 
     if (services == null) { 
      services = new HashMap<String, Service>(); 
      Map<String, Object> beans = context.getBeansWithAnnotation(ExampleAnnotation.class); 
      for (Object bean : beans.values()) { 
       ExampleAnnotation ann = bean.getClass().getAnnotation(ExampleAnnotation.class); 
       services.put(ann.value(), (Service) bean); 
      } 
     } 
    } 
} 
-1

Se i fagioli (A, B) di cui si sta parlando sono SessionScope, nessun problema, saranno selezionati correttamente.

public class BusinessLogic { 

    private BaseClassOfBeanAandB bean; 

    public void methodCalledByUserAorB() { 
    bean.doFoo(); 
    } 

} 
+0

Grazie. In questo caso non ci sono sessioni HTTP e i bean sono troppo pesanti per istanziare per richiesta. –

+0

Quindi come si può differire tra utente A e B? In base al parametro passato al metodo? – Manuel

+0

Sì. C'è un po 'di pre-autenticazione, così otteniamo gli ID utente passati (in realtà diversi parametri che si combinano per creare un'identità, ma questo è oltre il punto). –

2

Inserirli in una mappa suona bene. Se si tratta di una mappa gestita da Spring (usando util:map, o in configurazione Java), è meglio che crearla da qualche altra parte, perché in questo caso Spring possiede tutti i riferimenti agli oggetti e può gestire correttamente il loro ciclo di vita.

9

Affrontiamo questo problema nel nostro progetto e lo risolviamo attraverso una classe simile a quella di fabbrica. La classe di client -la uno che aveva bisogno il fagiolo a runtime- aveva un'istanza della fabbrica, che è stato iniettato attraverso Primavera:

@Component 
public class ImTheClient{ 

    @Autowired 
    private ImTheFactory factory; 

    public void doSomething(
      Parameters parameters) throws Exception{   
     IWantThis theInstance = factory.getInstance(parameters);   

    } 

} 

Così, l'istanza IWantThis dipende dal valore di runtime del parametro parameters. L'implementazione di fabbrica va come questa:

@Component 
public class ImTheFactoryImpl implements 
     ImTheFactory { 

    @Autowired 
    private IWantThisBadly anInstance; 
    @Autowired 
    private IAlsoWantThis anotherInstance; 

    @Override 
    public IWantThis getInstance(Parameters parameters) { 
     if (parameters.equals(Parameters.THIS)) { 
      return anInstance; 
     } 

     if (parameters.equals(Parameters.THAT)) { 
      return anotherInstance; 
     } 

     return null; 
    } 
} 

Così, l'istanza di fabbrica detiene riferimento sia dei valori posible della classe IWantThis, essendo IWantThisBadly e IAlsoWantThis entrambe le implementazioni di IWantThis.

+0

Una bella soluzione! :) – grozandrei

Problemi correlati