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.
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><?xml version="1.0" encoding="UTF-8"?>
<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">
<bean class="com.sanyou.spring.bean.injection.User"/>
</beans></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
Sanyou's Java Diary
Passionate about technology, though not great at solving problems; eager to share, never tire of learning!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.