A bean-factory post-processor works on registration metadata before ordinary application beans are created.
Spring BeanFactoryPostProcessor: inspect definitions before instances exist
The definition is the input
A receipt signer must be one shared instance because it owns a limited key handle. At container startup, a BeanFactoryPostProcessor can inspect the signer definition and reject a non-singleton scope before the application serves traffic. It operates on bean definitions, not the signer object. Scope choice] and constructor wiring] remain the ordinary first options; use a post-processor when one policy spans registrations you do not own.
Do not instantiate during definition work
Calling getBean inside the post-processor constructs an object before normal post-processing has finished. That object may miss proxy advice, property injection, or another extension step. The static @Bean method in the example lets the container register the post-processor without first creating its configuration object. BeanPostProcessor] works later on instances and has a different lifecycle risk.
Test failure at refresh
Register a prototype receiptSigner in a small application context and require refresh to fail with the scope message. Repeat with the singleton definition and assert one constructed signer. A unit call to the post-processor function can test the predicate, but only a context refresh proves Spring discovered it at the intended phase. Avoid using this hook for ordinary request validation or database access.
Implementation contract
@Configuration
class ReceiptDefinitionPolicy {
@Bean
static BeanFactoryPostProcessor signerScopeGuard() {
return factory -> {
BeanDefinition signer =
factory.getBeanDefinition("receiptSigner");
if (!signer.isSingleton()) {
throw new IllegalStateException(
"receiptSigner must use singleton scope");
}
};
}
}Cost and verification
The policy runs during context creation, so a failure blocks startup rather than a later request. A metadata scan is cheap; calling getBean here can trigger broad, premature initialization and make startup ordering hard to reason about.
Common Mistakes
- Do not call getBean from definition processing to inspect an application object.
- Do not declare a stateful non-static factory method for an early post-processor without understanding initialization order.
- Do not use container metadata hooks when a direct bean definition or constructor check expresses the rule.
Read next
Spring bean scopes: singleton identity is not thread safety, Spring BeanPostProcessor: instance callbacks and the early-bean trap, Spring constructor injection: required dependencies stay visible, Spring @Component versus @Bean: choose who constructs the dependency, Spring AOP proxies: self-invocation bypasses proxy advice.
