Dovrei usare un livello tra servizio e repository per un'architettura pulita - Spring

9

Sto lavorando in un'architettura, offrirò un ambiente di riposo per client web e app mobili. Sto usando Spring (spring mvc, spring data jpa, ... ecc.). Il modello di dominio è codificato con specifica JPA.

Sto cercando di applicare alcuni concetti di architettura pulita ( link ). Non tutto, perché ho intenzione di mantenere il modello del dominio jpa.

Il flusso effettivo attraverso i livelli è questo:

Front-end < - > Servizio API - > Servizio - > Repository - > DB

  • Front-end : client Web, app mobili
  • Servizio API : rest controller, qui uso convertitori e servizi dto e call
  • Servizio : si interfaccia con le implementazioni e contengono la logica aziendale
  • Repository : Interfacce del repository con implementazioni automatiche (eseguite da Spring Data jpa) che contamina le operazioni CRUD e forse alcune query SQL

Il mio dubbio: dovrei usare un livello aggiuntivo tra servizio e repository?

Sto pianificando questo nuovo flusso:

Front-end < - > Servizio API - > Servizio - > Persistenza - > Repository - > DB

Perché usare questo livello di persistenza? Come si dice nell'articolo di architettura pulita, vorrei avere un'implementazione di servizio (logica aziendale o caso d'uso) che acceda a un livello di persistenza agnostico. E non saranno necessarie modifiche se decido di utilizzare un altro pattern di "accesso ai dati", ad esempio se decido di smettere di usare il repository.

class ProductServiceImpl implements ProductService {
    ProductRepository productRepository;
    void save(Product product) {
        // do business logic
        productRepository.save(product)
    }
}

Quindi sto pensando di usare un livello di persistenza come questo:

class ProductServiceImpl implements ProductService {
    ProductPersistence productPersistence;
    void save(Product product) {
        // do business logic
        productPersistence.save(product)
    }
}

e implementazione del livello di persistenza in questo modo:

class ProductPersistenceImpl implements ProductPersistence {
    ProductRepository productRepository;
    void save(Product product) {
        productRepository.save(product)
    }
}

Quindi ho solo bisogno di cambiare le implementazioni del livello di persistenza, lasciato il servizio senza modifiche.Capito che il repository è correlato al framework.

Che ne pensi? Grazie.

    
posta Alejandro 10.05.2017 - 08:18
fonte

2 risposte

4

Front end <--> API Service -> Service -> Repository -> DB

Front end: web client, mobile apps

API Service: Rest Controllers, here I use converters and dto's and call services

Service: Interfaces with implementations and they contain business logic

Repository: Repository interfaces with automatically implementations(done by spring data jpa) which contatin CRUD operations and maybe some sql queries

Questo è il design proposto da Spring. Quindi sei in " Spring right right ".

I repository vengono comunemente chiamati DAO ma dal punto di vista del design, il repository e il DAO sono componenti diversi con responsabilità diverse.

Il modello del deposito appartiene a un livello più alto di astrazione. È un oggetto dominio. Più vicino all'azienda rispetto ai DAO.

In Spring JPA, il ruolo DAO è giocato da EntityManager . Gestisce le sessioni , l'accesso a DataSource , ecc.

Tradotto in componenti Spring, il tuo design è simile a:

@RestController > @Service > @Repository > EntityManager

Come vedi, il repository è già un'astrazione tra i servizi e l'archivio dati.

Se estendere i repository di Spring è eccessivo, puoi farlo

@Repository
public class MyRepositoryImpl implements MyRepository{
    private EntityManager em;

    public MyRepository (@Autowire EntityManager em){

           this.em = em;
     }

    //Interface implentation
    //...
}

Ora possiamo solo sostituire archivio dati .

@RestController > @Service > @Repository > RestTemplate

@Repository
public class MyRepositoryImpl implements MyRepository{
    private RestTemplate rt;

    public MyRepository (@Autowire RestTemplate rt){

           this.rt = rt;
     }

    //Interface implentation
    //...
}

@RestController > @Service > @Repository > File

@Repository
public class MyRepositoryImpl implements MyRepository{

    private File file; 
    public MyRepository (File file){

           this.file = file;
     }

    //Interface implentation
    //...
}

@RestController > @Service > @Repository > WebServiceClient

@Repository
public class MyRepositoryImpl implements MyRepository{

    private MyWebServiceClient wsClient; 
    public MyRepository (@Autowire MyWebServiceClient  wsClient){

           this.wsClient = wsClient;
     }

    //Interface implentation
    //...
}
L'interfaccia

MyRepository può o non può estendere l'interfaccia Repository di Spring. Dipende dalle tue esigenze Dai un'occhiata alla gerarchia delle interfacce.

Tornando alla domanda se dovresti aggiungere un altro livello di astrazione, direi di no, non è richiesto. Preferirei sfruttare le funzionalità del framework.

L'esempio che hai esposto, IMO, aggiunge solo più complessità. Il livello che proponi finirà come proxy tra servizi e repository o come pseudo-service-repository layer.

Infine, se le interfacce dei repository di Spring non sono sufficienti, se è necessario migliorare le interfacce e fornire nuovi metodi, Spring consente anche di farlo. Troverai esempi di googlatura di: BaseRepositoryFactoryBean implentation e @NoRepositoryBean

    
risposta data 10.05.2017 - 21:36
fonte
3

Il modo migliore per dimostrare che un design è flessibile è di renderlo flessibile.

Vuoi che un posto nel tuo codice sia responsabile della persistenza, ma non è legato all'idea di utilizzare un repository. Belle. Al momento non sta facendo nulla di utile ... sospiro, bene.

OK, testiamo se questo shunt layer ha funzionato. Crea un livello file flat che conserverà i tuoi prodotti nei file. Ora, dove questo nuovo livello va in questo design?

Bene dovrebbe essere in grado di andare dove è il DB. Dopotutto non abbiamo più bisogno di DB dato che stiamo usando file flat. Ma questo doveva anche non aver bisogno di un repository.

Considera, forse il repository è un dettaglio di implementazione. Dopotutto posso parlare al DB senza usare il modello di repository.

Front end <--> API Service -> Service -> Repository -> DB

Front end <--> API Service -> Service -> Repository -> Files

Front end <--> API Service -> Service -> Persistence -> DB

Front end <--> API Service -> Service -> Persistence -> Files

Se puoi fare tutto ciò che funziona senza toccare Service hai un codice flessibile.

Ma non credermi sulla parola. Scrivilo e guarda cosa succede. L'unico codice che considero flessibile è il codice flessibile.

    
risposta data 10.05.2017 - 21:31
fonte

Leggi altre domande sui tag