BeanFactoryPostProcessor

A BeanFactoryPostProcessor runs once at startup, after all bean definitions are registered and before any ordinary bean is created, to inspect or change them.

Why

Use it to adjust beans you did not declare yourself:

It sees definitions, not beans. Most applications never need one.

BeanDefinitionRegistryPostProcessor extends it. It can also add, remove or replace definitions. Use it when the set of beans is only known at startup: one bean per entry of a configuration file, one per plug-in found. Definitions it registers are seen by every later post-processor. For registering beans in code, a BeanRegistrar is usually simpler.

When they run

During refresh(), after the modules are loaded and before the bean graph is checked:

  1. the processors added with context.addBeanFactoryPostProcessor(...): postProcessBeanDefinitionRegistry of the registry processors;
  2. the BeanDefinitionRegistryPostProcessor beans, in three phases: PriorityOrdered, then Ordered or @Order, then the rest. The last phase repeats while they register more of themselves;
  3. postProcessBeanFactory of all registry processors, then of the regular processors added in code;
  4. the remaining BeanFactoryPostProcessor beans, in the same three phases.

Processors added in code run before the processor beans. One added after refresh() never runs.

Avoid creating beans in a post-processor, and keep its own dependencies few. A bean created here is created before the BeanPostProcessors exist and misses their processing.

Example

import 'package:spring_core_dart/spring_core_dart.dart';

abstract interface class Greeter {
  String greet(String name);
}

class German implements Greeter {
  @override
  String greet(String name) => 'Hallo, $name';
}

// The slow `reports` bean of a library starts on first use, not at startup.
@Component()
class MakeReportsLazy implements BeanFactoryPostProcessor {
  @override
  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    if (beanFactory.containsBeanDefinition('reports')) {
      beanFactory.getBeanDefinition('reports').lazy = true;
    }
  }
}

// Adds a German greeter, written by hand, to the scanned greeters.
@Component()
class GermanRegistrar implements BeanDefinitionRegistryPostProcessor {
  @override
  void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    registry.registerBeanDefinition(
      BeanDefinition<German>(
        name: 'german',
        types: const [German, Greeter],
        create: (_) => German(),
      ),
    );
  }

  @override
  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}
}

A processor that is not a bean:

final context = AnnotationConfigApplicationContext([appBeans])
  ..addBeanFactoryPostProcessor(MakeReportsLazy())
  ..refresh();

Members

Interface Method Meaning
BeanFactoryPostProcessor postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) Inspects or changes the definitions: scope, lazy, primary, fallback, autowireCandidate, defaultCandidate, order, description.
BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) Adds, removes or replaces definitions. Runs before every postProcessBeanFactory, its own included.

BeanDefinitionRegistry offers registerBeanDefinition, removeBeanDefinition, getBeanDefinition, containsBeanDefinition, beanDefinitionNames, beanDefinitionCount, registerAlias, removeAlias, isAlias and isBeanNameInUse. Registering a name that is already used fails with BeanDefinitionOverrideException, unless overriding is allowed.

In Spring (Java)

@Component
class MakeReportsLazy implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) {
    factory.getBeanDefinition("reports").setLazyInit(true);
  }
}

Differences that matter:

See also