How does Spring Data discover a fragment's Impl class, and how do you handle a non-default postfix or a manually-configured fragment bean?
answer
- Scan base packages for <Fragment><postfix>
- Constructor args resolved from context
- repositoryImplementationPostfix changes 'Impl'
- Explicit @Bean assignable to fragment overrides convention
- Impl outside base packages = not found
basics
~20 sSpring scans the repository's base packages for a class named <Fragment>Impl and instantiates it, injecting constructor dependencies. You can change the 'Impl' suffix via repositoryImplementationPostfix, or register the Impl as an explicit Spring bean when it needs special wiring.
solid answer
~50 sAt bootstrap, the repository infrastructure scans the configured base packages for each fragment's implementation by the classname convention (fragment name + postfix, default 'Impl'). It creates the instance and resolves constructor arguments from the ApplicationContext, so fragments can depend on EntityManager, other beans, etc. Two levers: first, the postfix is configurable — `@EnableJpaRepositories(repositoryImplementationPostfix = "Impl")` (or the equivalent XML/Boot property) changes it store-wide, useful to avoid clashes. Second, if a fragment implementation needs bespoke setup that convention can't provide (a bean produced by a @Bean factory method, profiles, qualifiers), you can declare it as an explicit Spring bean; Spring Data will detect an existing bean matching the fragment type and use it instead of instantiating a fresh one. Gotchas: the Impl must live within the scanned base packages, and its name/type must match, or composition silently omits it and startup fails on the unbacked method.
code
java · 20 lines// Non-default postfix, applied store-wide
@Configuration
@EnableJpaRepositories(
basePackages = "com.acme.repo",
repositoryImplementationPostfix = "CustomImpl")
class PersistenceConfig { }
// Now the impl for OrderRepositoryFragment must be:
class OrderRepositoryFragmentCustomImpl implements OrderRepositoryFragment { /* ... */ }
// Or take full control by declaring the fragment as an explicit bean:
@Configuration
class FragmentBeans {
@Bean
OrderRepositoryFragment orderRepositoryFragment(EntityManager em, PricingClient client) {
return new OrderRepositoryFragmentCustomImpl(em, client);
}
}
// Spring Data detects the existing bean assignable to the fragment type
// and composes it instead of instantiating one by convention.go deeper
Know discovery is by classname convention within scanned packages.
Explain constructor injection and the configurable postfix.
Cover explicit-bean override and package-scope failures in multi-module builds.
Standardize fragment packaging/naming and base-package config across a modular codebase to avoid silent misses.
## Discovery mechanism For every fragment interface a repository extends, Spring Data's `RepositoryFactoryBean` / configuration extension performs **implementation detection**: 1. Compute the expected implementation classname = fragment simple name + the **implementation postfix** (default `Impl`). 2. Look for such a class within the **base packages** configured for the repositories (the packages `@EnableJpaRepositories(basePackages=...)` scans, or the config-class package by default). 3. Instantiate it, resolving **constructor arguments** from the `ApplicationContext` — this is how a fragment gets an `EntityManager`, a `JdbcTemplate`, a `RestClient`, etc. 4. Add it to the repository's `RepositoryComposition`. Importantly, the Impl is treated like a Spring-managed collaborator for the purpose of dependency injection even though you didn't annotate it `@Component`. ## Changing the postfix The default `Impl` is configurable per store module: ```java @EnableJpaRepositories( basePackages = "com.acme.repo", repositoryImplementationPostfix = "Impl") ``` Set it (e.g., to `CustomImpl`) if your naming would otherwise collide with existing `*Impl` classes or team conventions. All fragment impls must then use that postfix. There are equivalent attributes for the other store modules (`@EnableMongoRepositories`, etc.) and the XML `repository-impl-postfix` attribute. ## Manually-declared fragment bean When convention isn't enough — the impl needs a `@Bean` factory method, a profile, a `@Qualifier`, or complex construction — declare it as an explicit bean: ```java @Bean OrderRepositoryCustom orderRepositoryCustom(EntityManager em, PricingClient c) { return new OrderRepositoryCustomImpl(em, c); } ``` Spring Data detects a **pre-existing bean assignable to the fragment interface** and composes that instead of instantiating one itself. This lets you fully control construction. ## Gotchas - **Package scope**: the Impl must be inside the scanned base packages. A fragment interface in a shared/library package with its Impl outside the app's `basePackages` won't be found. - **Name/type mismatch**: any deviation from `<Fragment><postfix>` (typo, wrong postfix) means the fragment is unbacked; you get a startup failure such as `No property/implementation found` or a `BeanCreationException` about an abstract method. - **Ambiguity**: two candidate beans assignable to a fragment type can produce an ambiguity error; use `@Qualifier` or a single bean. - **Boot**: Spring Boot's auto-config sets sensible base packages (the main class package). Splitting fragments into a jar without adjusting `basePackages` is a frequent 'why isn't my Impl found' cause.
- Your fragment interface lives in a shared library jar and the Impl isn't found. What's the usual cause?The Impl class isn't within the repository scan base packages. Either move it into a scanned package or extend basePackages in @EnableJpaRepositories to cover it.
- When would you register the fragment Impl as an explicit @Bean instead of relying on convention?When construction needs a factory method, profile, qualifier, or collaborators the convention-based instantiation can't supply. Spring Data uses an existing bean assignable to the fragment type over creating its own.
saying these in an interview costs you the question
- Assuming the Impl is found anywhere on the classpath regardless of base packages
- Thinking the postfix cannot be changed
- Believing you must annotate the Impl @Component for injection to work