Em primeiro lugar, não há geração de código em andamento, o que significa: sem CGLib, nenhuma geração de código de byte. A abordagem fundamental é que uma instância do proxy JDK é criada programaticamente usando a ProxyFactory
API do Spring para apoiar a interface e MethodInterceptor
intercepta todas as chamadas para a instância e encaminha o método para os locais apropriados:
- Se o repositório foi inicializado com uma parte de implementação customizada (consulte essa parte da documentação de referência para obter detalhes), e o método chamado foi implementado nessa classe, a chamada é roteada para lá.
- Se o método for um método de consulta (veja
DefaultRepositoryInformation
como isso é determinado), o mecanismo de execução de consulta específico da loja entra em ação e executa a consulta determinada a ser executada para aquele método na inicialização. Para isso, existe um mecanismo de resolução que tenta identificar consultas declaradas explicitamente em vários lugares (usando @Query
no método, consultas nomeadas JPA), eventualmente voltando para a derivação da consulta a partir do nome do método. Para a detecção do mecanismo de consulta, consulteJpaQueryLookupStrategy
. A lógica de análise para a derivação da consulta pode ser encontrada em PartTree
. A tradução específica da loja em uma consulta real pode ser vista, por exemplo, em JpaQueryCreator
.
- Se nenhuma das opções acima se aplicar, o método executado deve ser implementado por uma classe base de repositório específica da loja (
SimpleJpaRepository
no caso de JPA) e a chamada é roteada para uma instância desse.
O método interceptor que implementa essa lógica de roteamento é QueryExecutorMethodInterceptor
, a lógica de roteamento de alto nível pode ser encontrada aqui .
A criação desses proxies é encapsulada em uma implementação padrão de fábrica baseada em Java. A criação de proxy de alto nível pode ser encontrada emRepositoryFactorySupport
. Em seguida, as implementações específicas da loja adicionam os componentes de infraestrutura necessários para que, para JPA, você possa seguir em frente e apenas escrever o código como este:
EntityManager em = … // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);
O motivo pelo qual menciono isso explicitamente é que deve ficar claro que, em seu núcleo, nada desse código exige que um contêiner Spring seja executado em primeiro lugar. Ele precisa do Spring como uma biblioteca no caminho de classe (porque preferimos não reinventar a roda), mas é agnóstico de contêiner em geral.
Para facilitar a integração com os contêineres DI, é claro que construímos a integração com a configuração Spring Java, um namespace XML, mas também uma extensão CDI , para que o Spring Data possa ser usado em cenários CDI simples.
@Repository
interfaces anotadas em primeiro lugar? Olhando paraRepositoryFactorySupport#getRepository()
mostrar que leva a classe de interface como parâmetro, deve ser descoberta em outro lugar. Estou particularmente tentando descobrir como encontrar uma interface anotada e gerar automaticamente um bean de proxy JDK que implementa a interface, muito parecido com spring-data, mas para um propósito específico de aplicativo não relacionado a Repositórios.RepositoryComponentProvider
. Não há coisas automáticas acontecendo, mas uma varredura de componente para certos tipos (seja anotado ou carregando uma anotação) e umFactoryBean
configurado para cada um deles.