Backend Development 18 min read

Mastering Spring Bean Injection: 5 Ways to Register Beans in the Container

This article comprehensively reviews the various techniques for injecting beans into the Spring container—including XML and properties configuration files, annotation-based declarations, manual BeanDefinition registration, direct singleton registration, and FactoryBean usage—providing code examples, underlying principles, and practical guidance for each method.

Sanyou's Java Diary
Sanyou's Java Diary
Sanyou's Java Diary
Mastering Spring Bean Injection: 5 Ways to Register Beans in the Container

Hello, I am Sanyou. This article explores the different ways to inject beans into Spring.

Many existing articles miss completeness, the reasons behind each injection method, and source code examples. This article addresses those gaps.

Configuration Files

Configuration files allow external declaration of Spring beans. Although less common today, Spring still supports XML and properties formats.

XML

Example XmlBeanInjectionDemo.xml declares a User bean.

<code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    &lt;bean class="com.sanyou.spring.bean.injection.User"/&gt;
&lt;/beans&gt;</code>

Corresponding User class:

<code>@Data
@ToString
public class User {
    private String username;
}</code>

Test class loads the bean via ClassPathXmlApplicationContext and prints the result.

<code>public class XmlBeanInjectionDemo {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:XmlBeanInjectionDemo.xml");
        applicationContext.refresh();
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }
}</code>

Result shows User(username=null) , indicating successful injection with a null username property.

Properties

Spring also supports properties files for bean declaration.

Example PropertiesBeanInjectionDemo.properties sets the bean class and a username value.

<code>user.(class)=com.sanyou.spring.bean.injection.User
user.username=sanyou</code>

Test class loads the bean using GenericApplicationContext and PropertiesBeanDefinitionReader .

<code>public class PropertiesBeanInjectionDemo {
    public static void main(String[] args) {
        GenericApplicationContext applicationContext = new GenericApplicationContext();
        PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(applicationContext);
        Resource classPathResource = new ClassPathResource("PropertiesBeanInjectionDemo.properties");
        propReader.loadBeanDefinitions(classPathResource);
        applicationContext.refresh();
        User user = applicationContext.getBean(User.class);
        System.out.println(user);
    }
}</code>

Result shows User(username=sanyou) , confirming the property value was applied.

Annotation Declaration

Configuration files become cumbersome as projects grow, so Spring 2.x introduced annotation‑based bean declaration.

@Component + @ComponentScan

Custom business classes annotated with @Component (or its derivatives such as @Service , @Controller ) are automatically registered. In Spring Boot, @SpringBootApplication includes @ComponentScan by default.

@Bean

@Bean is used for third‑party classes that lack @Component . Example shows registering a MyBatis‑Plus pagination interceptor.

<code>@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    return interceptor;
}</code>

@Import

@Import can import ordinary classes, ImportSelector implementations, or ImportBeanDefinitionRegistrar implementations.

Ordinary class

Simply registers the imported class as a bean.

ImportSelector

<code>public interface ImportSelector {
    String[] selectImports(AnnotationMetadata importingClassMetadata);
    default Predicate<String> getExclusionFilter() { return null; }
}</code>

Example UserImportSelector returns the fully‑qualified name of User .

<code>public class UserImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        System.out.println("Calling UserImportSelector.selectImports");
        return new String[]{"com.sanyou.spring.bean.injection.User"};
    }
}</code>

Demo imports the selector and retrieves the bean.

<code>@Import(UserImportSelector.class)
public class ImportSelectorDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(ImportSelectorDemo.class);
        ctx.refresh();
        User user = ctx.getBean(User.class);
        System.out.println(user);
    }
}</code>

Result: User(username=null) .

ImportBeanDefinitionRegistrar

This interface allows manual creation and registration of BeanDefinition objects.

<code>public class UserImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry,
                                        BeanNameGenerator importBeanNameGenerator) {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
            .rootBeanDefinition(User.class)
            .addPropertyValue("username", "三友的java日记")
            .getBeanDefinition();
        registry.registerBeanDefinition("user", beanDefinition);
    }
}</code>

Demo registers the bean and prints the injected instance.

<code>@Import(UserImportBeanDefinitionRegistrar.class)
public class UserImportBeanDefinitionRegistrarDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(UserImportBeanDefinitionRegistrarDemo.class);
        ctx.refresh();
        User user = ctx.getBean(User.class);
        System.out.println(user);
    }
}</code>

Result: User(username=三友的java日记) .

BeanDefinitionRegistryPostProcessor

Another way to obtain BeanDefinitionRegistry ; demonstration omitted for brevity.

OpenFeign uses ImportBeanDefinitionRegistrar to register FeignClientFactoryBean for each @FeignClient interface.

<code>class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar { ... }</code>

Register Created Bean

Instead of registering a definition, a fully created bean can be added directly to the singleton registry via ConfigurableListableBeanFactory , which extends SingletonBeanRegistry .

BeanFactoryPostProcessor can obtain the factory.

Demo registers a User instance as a singleton.

<code>public class RegisterUserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        User user = new User();
        user.setUsername("三友的java日记");
        beanFactory.registerSingleton("user", user);
    }
}</code>

Test retrieves the bean.

<code>public class RegisterUserDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(RegisterUserBeanFactoryPostProcessor.class);
        ctx.refresh();
        User user = ctx.getBean(User.class);
        System.out.println(user);
    }
}</code>

Result: User(username=三友的java日记) . This pattern is widely used for internal Spring beans.

FactoryBean

FactoryBean is a special bean whose getObject() creates the actual bean instance.

Example UserFactoryBean returns a User with a preset username.

<code>public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        User user = new User();
        user.setUsername("三友的java日记");
        return user;
    }
    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}</code>

Demo registers the factory bean and obtains the User bean.

<code>public class UserFactoryBeanDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(UserFactoryBean.class);
        ctx.refresh();
        User user = ctx.getBean(User.class);
        System.out.println(user);
    }
}</code>

Result: User(username=三友的java日记) . OpenFeign also uses a FactoryBean implementation ( FeignClientFactoryBean ) to create client proxies.

<code>class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware { ... }</code>

Conclusion

Bean injection into the Spring container can be grouped into five categories: configuration files, annotation declaration, manual BeanDefinition registration, direct singleton registration, and FactoryBean . Annotation‑based injection is the most common in everyday development, while third‑party framework integrations often rely on BeanDefinition or FactoryBean registration. Configuration‑file and direct singleton approaches exist but are used less frequently.

https://github.com/sanyou3/spring-bean-injection.git
JavaBackend DevelopmentSpringdependency injectionSpring FrameworkBean Injection
Sanyou's Java Diary
Written by

Sanyou's Java Diary

Passionate about technology, though not great at solving problems; eager to share, never tire of learning!

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.