Resolving bean conflicts, what really happens when auto-configurations define the same bean, XML vs annotations, Mockito @Spy vs @Mock, join points vs pointcuts, Spring Batch end to end, how @Autowired resolves dependencies, why constructor injection wins, AOP and its biggest drawback, and preventing cyclic dependencies.
Published September 25, 2026
These questions test whether you understand Spring's resolution rules: which bean gets injected, and which configuration wins. They also test cross-cutting features (AOP, Batch). Several common answers are outdated for Spring Boot 2.1+, so give the current behaviour.
Short answer: First, identify the kind of conflict:
NoUniqueBeanDefinitionException): mark the default with @Primary, or pick one at the injection point with @Qualifier. Or inject a List/Map of all of them, and choose at runtime.BeanDefinitionOverrideException): rename one of them. Or, only if you really intend an override, set spring.main.allow-bean-definition-overriding=true.@ConditionalOnMissingBean).Short answer: Well-written auto-configurations guard their beans with @ConditionalOnMissingBean. The first one to be evaluated registers the bean, and the others back off. The evaluation order is controlled by @AutoConfiguration(before = …, after = …) / @AutoConfigureOrder. User configuration is always processed before auto-configuration, so your beans take priority.
If two definitions actually collide by name without such conditions, Spring Boot (since 2.1) fails at startup, because bean-definition overriding is disabled by default.
Common trap: "the last one read wins". That was plain Spring's historical behaviour (silent overriding), and Boot deliberately turned it off, because silent overrides caused hard-to-find bugs.
Learn it in depth → Auto-Configuration Mechanism
Short answer: Annotations and Java configuration. They're type-safe (refactoring and IDE navigation work), sit next to the code they configure, can use conditions and profiles in code, and are what Spring Boot is designed around. XML still appears in legacy systems. Its original selling point (changing wiring without recompiling) is now served better by externalised properties and profiles.
Key points to cover:
@Configuration classes for third-party objects and wiring decisions, and stereotypes plus constructor injection for your own classes.@Spy and @Mock in Mockito?Short answer: A @Mock is a complete fake. Every method returns a default (null, 0, an empty collection) unless you stub it, and no real code runs. A @Spy wraps a real object. Real methods run, unless you stub specific ones.
@Spy List<String> spyList = new ArrayList<>();
@Mock List<String> mockList;
spyList.add("a"); // really added → spyList.size() == 1
mockList.add("a"); // does nothing → mockList.size() == 0 (unstubbed default)
doReturn(100).when(spyList).size(); // use doReturn with spies: when(spy.size()) would call the real method first
Key points to cover:
Learn it in depth → Mockito Basics
Short answer: A join point is a point in program execution where an aspect could apply. In Spring AOP, it's always a method execution on a Spring bean. A pointcut is an expression that selects a set of join points. Advice is the code that runs at the selected join points (@Before, @AfterReturning, @AfterThrowing, @After, @Around). An aspect bundles pointcuts and advice.
@Aspect
@Component
class TimingAspect {
@Pointcut("within(com.shop..service..*) && execution(public * *(..))") // the pointcut: which join points
void serviceMethods() { }
@Around("serviceMethods()") // the advice
Object time(ProceedingJoinPoint jp) throws Throwable { // jp = the current join point
long start = System.nanoTime();
try { return jp.proceed(); }
finally { log.info("{} took {} µs", jp.getSignature().toShortString(), (System.nanoTime() - start) / 1000); }
}
}
Learn it in depth → Spring AOP
Short answer: Spring Batch processes large volumes of data reliably in the background: nightly settlements, file imports, report generation, data migrations. It provides chunk-oriented processing, restartability (it tracks progress in its job repository tables), skip and retry policies, and partitioning for scale.
The steps:
Job, made of one or more Steps.ItemReader (a flat file, JDBC cursor or paging reader), an ItemProcessor (validation and transformation) and an ItemWriter (a database, file or API), plus a chunk size. Each chunk is committed in its own transaction.skip for bad records (with a limit), retry for transient errors, and listeners for logging.@Bean
Step importTransactions(JobRepository repo, PlatformTransactionManager tx,
FlatFileItemReader<TxnLine> reader, TxnProcessor processor, JdbcBatchItemWriter<Txn> writer) {
return new StepBuilder("importTransactions", repo)
.<TxnLine, Txn>chunk(500, tx)
.reader(reader).processor(processor).writer(writer)
.faultTolerant().skip(ParseException.class).skipLimit(100)
.retry(TransientDataAccessException.class).retryLimit(3)
.build();
}
Key points to cover:
JobBuilderFactory and StepBuilderFactory. You pass the JobRepository explicitly, as shown above.@Autowired perform?Short answer: @Autowired resolves a dependency by type. If several beans match, it narrows the choice using @Qualifier, then @Primary, then the parameter or field name as a fallback. It can be applied to a constructor, a setter or other method, or a field, and the injection style is whichever you annotate. Since Spring 4.3, a class with a single constructor gets constructor injection even without @Autowired.
Common trap: "@Autowired uses constructor injection by default". The annotation has no default style. Constructor injection is the recommended practice.
Short answer:
final fields make it immutable, and safe to publish across threads.new Service(mockA, mockB).Setter injection remains useful for optional or re-configurable dependencies.
Short answer: Aspect-Oriented Programming modularises cross-cutting concerns (transactions, security, logging, metrics, caching, retries) into aspects that are applied declaratively, instead of being scattered through the business code. In Spring, AOP powers @Transactional, @Cacheable, @Async, @PreAuthorize and @Retryable.
Its biggest disadvantage: hidden control flow. Behaviour happens without appearing in the code you're reading, which makes debugging and onboarding harder. Spring's proxy-based implementation adds pitfalls:
final and private methods aren't advised.@Order).Short answer:
ApplicationEventPublisher) instead of direct references.Common trap: "switch to setter or field injection". That hides the cycle, and doesn't even work on Spring Boot 2.6+ unless you opt back into circular references.
Q: What's the difference between JDK dynamic proxies and CGLIB proxies?
A: JDK proxies implement the bean's interfaces, so callers must use the interface type. CGLIB creates a subclass of the bean class, so it works without interfaces, but can't intercept final methods. Spring Boot defaults to CGLIB (proxyTargetClass=true).
Q: How do you order several aspects on the same method?
A: Annotate the aspect classes with @Order (or implement Ordered). A lower value means higher precedence: it runs first on the way in, and last on the way out.
Q: Where should a Spring Batch job's state live?
A: In the job repository, the BATCH_* tables in a real database. That lets a failed job restart from its last committed chunk. An in-memory repository loses the progress.
Q: What's the difference between AspectJ and Spring AOP? A: Spring AOP is proxy-based: method execution on Spring beans only, woven at runtime. AspectJ weaves bytecode (at compile or load time), so it can intercept constructors, field access, private methods and self-calls, at the cost of more build and runtime setup.