Ramon, acredito que vc interpretou errado a boa prática.
Primeiro porque não faz sentido nós, os programadores, implementarmos os repositórios porque quem implementa por nós automáticamente é o Spring Data.
Segundo que a boa prática, até onde entendo, diz pra gente dividir as camadas. Os repositórios ficam só com o acesso ao banco, os controladores lidam com as requisições e, no meio destes dois, nós temos os serviços.
Então vc teria um cenário assim:
@Repository
interface PessoaRepository extends JpaRepository<Pessoa, Integer> {
Pessoa findById(int id);
List<Pessoa> findAll();
String findByName(String name);
}
@Service
class PessoaService {
@Autowired
private PessoaRepository repository;
List<Pessoa> findAll() {
// Aqui vai qualquer lógica de negócio
return repository.findAll();
}
}
@RestController
class PessoaController {
@Autowired
private PessoaService service;
@GetMapping
List<Pessoa> index() {
return service.findAll();
}
}
Atente para o comentário indicando o lugar da lógica de negócio. Com esta configuração evitamos que o controlador faça mais do que deveria.
Uma coisa comum também é o seguinte: Ao invés de criar PessoaService como uma classe concreta, vc pode separa em 2 partes, a interface e a implementação. Neste caso seria assim:
interface PessoaService {
List<Pessoa> findAll();
}
@Service
class PessoaServiceImpl implements PessoaService {
@Autowired
private PessoaRepository repository;
@Override
public List<Pessoa> findAll() {
// Aqui vai qualquer lógica de negócio
return repository.findAll();
}
}
Mesmo separando desta forma, o código do seu controlador não mudará, ele continuará dependendo de PessoaService e o Spring se encarregará de encontrar sua implementação e injetá-la corretamente.