Backend Development 10 min read

Master Spring Bean Injection: XML, Annotations, FactoryBean & RegistryPostProcessor

Explore multiple Spring bean injection techniques—including XML configuration, annotation-driven @Configuration/@Bean, @Import, FactoryBean, and BeanDefinitionRegistryPostProcessor—through clear explanations, code samples, and practical examples, highlighting their advantages, drawbacks, and how to integrate them into a Spring application.

macrozheng
macrozheng
macrozheng
Master Spring Bean Injection: XML, Annotations, FactoryBean & RegistryPostProcessor

When Spring is mentioned, most people think of AOP and IOC, but the framework also provides several ways to inject beans into the container. This article examines the main Spring IOC features and presents four injection methods: XML configuration, annotation-based configuration, FactoryBean, and BeanDefinitionRegistryPostProcessor.

XML Configuration

Early Spring projects often used XML files to declare beans. The injection can be performed via setter, constructor, or field injection, supporting both value and reference types.

Example of setter injection using XML:

<code>&lt;bean name="teacher" class="org.springframework.demo.model.Teacher"&gt;
    &lt;property name="name" value="阿Q"&gt;&lt;/property&gt;
&lt;/bean&gt;</code>

Corresponding Java class:

<code>public class Teacher {
    private String name;
    public void setName(String name) { this.name = name; }
}</code>

Drawbacks of XML configuration:

Configuration files are cumbersome to maintain alongside code, reducing development efficiency.

Large projects accumulate many XML files, making maintenance difficult.

Configuration errors are only detected at runtime, not during compilation.

Parsing XML consumes memory resources and can affect performance.

Annotation-Based Configuration

Since Spring 2.5, annotations such as @Controller, @Service, @Repository, and @Component have been widely used. Two common annotation approaches are @Configuration + @Bean and @Import.

@Configuration + @Bean

@Configuration declares a configuration class, similar to the

&lt;beans&gt;

tag in XML, while @Bean marks a method that returns a bean instance, analogous to the

&lt;bean&gt;

tag.

Simple example: injecting a RedisTemplate bean.

<code>@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // ... configure redisTemplate ...
        return redisTemplate;
    }
}</code>

@Import

@Import can import third‑party configuration classes or custom selectors. It works only on classes.

Example using a custom ImportSelector:

<code>@Configuration
@Import(MyImportSelector.class)
public class MyConfig {}

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"org.springframework.demo.model.Teacher", "org.springframework.demo.model.Student"};
    }
}</code>

ImportBeanDefinitionRegistrar can also register beans programmatically:

<code>@Configuration
@Import(value = {MyImportBeanDefinitionRegistrar.class})
public class MyConfig {}

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition tDefinition = new RootBeanDefinition(Teacher.class);
        registry.registerBeanDefinition("teacher", tDefinition);
    }
}</code>

FactoryBean

FactoryBean is a special bean that creates other objects, similar to the factory pattern. It allows custom creation logic while still being managed by the Spring container.

<code>public class TeacherFactoryBean implements FactoryBean<Teacher> {
    @Override
    public Teacher getObject() throws Exception { return new Teacher(); }
    @Override
    public Class<?> getObjectType() { return Teacher.class; }
}</code>

Register the FactoryBean using @Configuration + @Bean:

<code>@Configuration
public class MyConfig {
    @Bean
    public TeacherFactoryBean teacherFactoryBean() { return new TeacherFactoryBean(); }
}</code>

When requesting a

Teacher

bean, Spring will invoke the FactoryBean to obtain the actual instance.

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor and allows registration of additional bean definitions before the container refreshes.

<code>public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}</code>

Spring internally invokes these post‑processors during startup:

<code>while (reiterate) {
    // ...
    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    // ...
}</code>

Custom implementation example:

<code>public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        RootBeanDefinition bd = new RootBeanDefinition(Teacher.class);
        registry.registerBeanDefinition("teacher", bd);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}</code>

Bootstrapping the custom post‑processor:

<code>public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    MyBeanDefinitionRegistryPostProcessor postProcessor = new MyBeanDefinitionRegistryPostProcessor();
    context.addBeanFactoryPostProcessor(postProcessor);
    context.refresh();
    Teacher bean = context.getBean(Teacher.class);
    System.out.println(bean);
}</code>

The output shows that the

Teacher

bean has been successfully registered and retrieved from the Spring container.

In short, Spring now creates and controls objects for you, shifting the responsibility of object creation from the developer to the framework.
BackendJavaSpringdependency injectionFactoryBeanBeanDefinitionRegistryPostProcessor
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.