skip to content

Repository Proxy Generation

At startup Spring Data scans your interfaces and generates a JDK dynamic-proxy implementation for each, backed by a factory that knows the store. Explaining this is the answer to the interview classic 'who implements this interface'.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

You declare a Spring Data repository as just an interface with no body. Who provides the actual implementation, and when?

level: juniorimportance: must knowfreq 72%

answer

  1. Interface only, no Impl
  2. Proxy generated at startup
  3. SimpleJpaRepository = CRUD base
  4. Query methods derived from name / @Query
  5. Fail fast at context load

basics

~20 s

You never write the implementation. Spring Data creates it for you automatically at application startup — it generates a proxy object that implements your repository interface and wires it into the Spring container as a bean.

solid answer

~40 s

A Spring Data repository is a plain interface (e.g. extending JpaRepository). You never implement it. At startup, Spring Data's infrastructure scans for these interfaces and, for each one, produces a runtime proxy object that implements the interface. That proxy becomes the Spring bean you inject. When you call a method on it, the proxy either forwards to a built-in base implementation (SimpleJpaRepository for CRUD methods like save/findById) or executes a query it derived from the method name or from an @Query annotation. Because everything is generated at container startup, misconfigured queries or missing base packages typically fail fast when the context loads, not at first use. The developer's job is only to declare methods; the framework supplies behavior.

go deeper

for a junior

Must know that you write only the interface and the framework generates the implementation at startup.

for a middle

Should be able to name SimpleJpaRepository as the CRUD base and explain derived-vs-@Query routing.

for a senior

Frames it as proxy generation over interfaces with fail-fast startup semantics.

for a principal

Connects declarative repositories to the broader programming model and startup-cost / bootstrap-mode trade-offs.

**The core idea.** In Spring Data you write repositories as *interfaces*, not classes. For example: ```java public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); } ``` There is no `UserRepositoryImpl` that you write. Yet you can `@Autowired UserRepository` and call `save`, `findById`, and `findByEmail`. Something must be providing a concrete object. **What actually happens.** During Spring's application-context startup, Spring Data's infrastructure (triggered by `@EnableJpaRepositories`, or auto-configured by Spring Boot) finds every interface that extends a Spring Data `Repository` marker (like `JpaRepository`, `CrudRepository`, `PagingAndSortingRepository`). For each interface it creates a **proxy** — a dynamically generated object that implements that interface — and registers it as a bean in the container. That proxy is what gets injected when you `@Autowired`. **Where the behavior comes from.** The proxy does not contain hand-written logic for each method. Instead, when you call a method it routes the call: - **CRUD / base methods** (`save`, `findById`, `delete`, `count`, …) go to a framework-provided base class instance — for JPA that is `SimpleJpaRepository`, which uses the `EntityManager` under the hood. - **Query methods** you declared (`findByEmail`) are handled by a query Spring Data built at startup, either by *deriving* it from the method name (`findByEmail` → `where email = ?`) or from an explicit `@Query`. **Terms defined.** - *Proxy*: an object generated at runtime that implements an interface and intercepts calls to it so the framework can insert behavior. - *Bean*: an object managed by the Spring container (created, configured, injected for you). - *SimpleJpaRepository*: Spring Data JPA's default implementation of the standard CRUD/paging operations. **When it happens / why it matters.** All this generation occurs at *startup*, not lazily at first call (with the default bootstrap mode). A key practical consequence: many mistakes — an invalid `@Query`, a derived method name that references a non-existent property, or repositories in a package the scanner doesn't cover — surface as a startup failure, which is exactly what you want (fail fast). **Gotcha.** A repository interface that is *not* on a scanned base package will simply have no bean created, and injection fails with 'no qualifying bean' — people often mistake this for the framework being 'broken' when really the interface was outside the scanned packages.

  • If you never write the implementation, how does findByEmail know what SQL/JPQL to run?
    At startup Spring Data parses the method name into a query (property 'email', keyword equality) or reads an explicit @Query, builds a RepositoryQuery object, and the proxy invokes it when the method is called.
  • What happens if the repository interface is in a package not covered by the scan?
    No proxy bean is created for it, so injecting it fails with a 'no qualifying bean of type' error at startup — a configuration/base-package problem, not a framework bug.

context

open as a page

What kind of proxy does Spring Data create for a repository, and which class actually builds it?

level: middleimportance: should knowfreq 55%

basics

~20 s

A JDK dynamic proxy — because repositories are interfaces, no subclassing (CGLIB) is needed. The proxy is assembled by RepositoryFactorySupport (the JPA subclass is JpaRepositoryFactory) using Spring AOP's ProxyFactory, which adds interceptors before creating the interface-based proxy.

open as a page

Walk through how @EnableJpaRepositories turns your repository interfaces into beans. What is the role of RepositoryFactoryBean?

level: seniorimportance: should knowfreq 48%

basics

~20 s

@EnableJpaRepositories imports a registrar that scans the base packages for repository interfaces. For each one it registers a bean definition whose class is JpaRepositoryFactoryBean. That FactoryBean, at startup, uses a RepositoryFactory to build and hand back the proxy as the actual bean.

open as a page

What is a RepositoryProxyPostProcessor, when in the lifecycle is it invoked, and give real examples of what it contributes.

level: seniorimportance: should knowfreq 34%

basics

~20 s

It is a callback that lets Spring Data add AOP advice to a repository proxy before the proxy is created. During getRepository(), each registered post-processor's postProcess(ProxyFactory, RepositoryInformation) runs. Examples: adding transaction interception and JPA exception translation.

open as a page

At runtime, when you call a method on the generated repository proxy, how does it decide what to actually execute? And what is resolved eagerly at startup versus per call?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Every call goes through the proxy's QueryExecutorMethodInterceptor, which classifies the method: a declared query method runs a pre-built RepositoryQuery; a custom-fragment or default method goes to that implementation; a base CRUD method goes to SimpleJpaRepository. Query objects and metadata are built at startup; dispatch happens per call.

open as a page