Spring容器注入Bean的N种方式
学过Spring应该都知道Spring最核心的功能之一就是可以帮我们管理Bean。当然,Bean不是无中生有的,需要我们按照Spring的规则做配置,Spring容器中才会有。那么到底有多少种配置方式可以往容器注入Bean呢,今天做个简单总结。
一 <bean id="" class=""/>
这个应该是最最基础的了,基本上学Spring都是从这种方式开始的。在Spring配置文件中的每一个bean标签都对应一个bean。代码如下:
public class Student {
private Integer id;
private String name;
public Student() {
}
public Student(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void study(){
System.out.println("今天不学习,明天变垃圾");
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
<bean id="xiaoming" class="com.study.spring.bean.Student">
<property name="id" value="007"></property>
<property name="name" value="xiaoming"></property>
</bean>
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext=
new ClassPathXmlApplicationContext("applicationContext.xml");
Student xiaoming = applicationContext.getBean("xiaoming", Student.class);
System.out.println(xiaoming);
}
}
二 <bean id="" factory-bean="" factory-method=""/>
通过实例工厂方法创建
public class StudentFactoryBean {
public Student instance(){
return new Student();
}
}
<bean id="studentFactoryBean" class="com.study.spring.config.StudentFactoryBean"/>
<bean id="student" factory-bean="studentFactoryBean" factory-method="instance"/>
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext=
new ClassPathXmlApplicationContext("applicationContext.xml");
Student student=classPathXmlApplicationContext.getBean(Student.class);
System.out.println(student);
}
}
三 <bean id="" class="" factory-method=""/>
通过静态工厂方法创建
public class StaticStudentFactoryBean {
public static Student getInstance(){
return new Student();
}
}
<bean id="student" class="com.study.spring.config.StaticStudentFactoryBean" factory-method="getInstance"/>
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext=
new ClassPathXmlApplicationContext("applicationContext.xml");
Student student=classPathXmlApplicationContext.getBean(Student.class);
System.out.println(student);
}
}
四 <context:component-scan/> + @Component
在context:component-scan标签扫描范围内且并未排除的,标了Component(Controller,Service,Repository)注解都可以成为Bean。代码如下。
<context:component-scan base-package="com.study.spring"/>
@Component
public class Student {
。。。
}
五 @Configuration + @Bean
随着纯注解编程越来越普及,这种方式用得相当多,很多优秀的开源框架都在用
@Configuration
public class MyConfig {
@Bean
public Student student(){
return new Student(007,"xiaoming");
}
}
六 @Component + @ComponentScan
@Component
public class Student {
。。。
}
@ComponentScan(basePackages = "com.study.spring.*")
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(Test.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
七 @Import直接注入一个bean
我们自己用得不多,但是在基于springboot的框架中被大量使用,如springcloud系列
@Configuration
@Import(Student.class)
public class MyConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
八 ImportSelector + @Import
ImportSelector 的selectImports方法返回的是字符窜数组,所以可以一次导入多个bean
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.study.spring.bean.Student"};
}
}
@Configuration
@Import(MyImportSelector.class)
public class MyConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
九 DeferredImportSelector + @Import
public class MyDeferredSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{Student.class.getName()};
}
}
@Configuration
@Import(MyDeferredSelector.class)
public class MyConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
提示:
1. DeferredImportSelector是ImportSelector的扩展;
2. ImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理之前,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理;
3. DeferredImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理完毕之后,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理;
4. DeferredImportSelector的实现类可以用Order注解,或者实现Ordered接口来对selectImports的执行顺序排序;
十 ImportBeanDefinitionRegistrar + @Import
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AbstractBeanDefinition abstractBeanDefinition=
BeanDefinitionBuilder.rootBeanDefinition(Student.class).getBeanDefinition();
registry.registerBeanDefinition("student",abstractBeanDefinition);
}
}
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyConfig {
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
十一 FactoryBean 接口
public class StudentFactoryBean implements FactoryBean<Student> {
@Override
public Student getObject() throws Exception {
return new Student();
}
@Override
public Class<?> getObjectType() {
return Student.class;
}
@Override
public boolean isSingleton() {
return true;//返回true,表示返回的Student是单例的,每次获取的是同一个对象,返回false,每次获取的不是同一个对象。
}
}
@Configuration
public class MyConfig {
@Bean
public StudentFactoryBean studentFactoryBean(){
return new StudentFactoryBean();
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext(MyConfig.class);
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
十二 BeanDefinitionRegistryPostProcessor 接口
这是利用了bean定义注册器后置处理器,后置处理器这个概念在spring中无处不在
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry)
throws BeansException {
AbstractBeanDefinition abstractBeanDefinition=
BeanDefinitionBuilder.rootBeanDefinition(Student.class).getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition("student",abstractBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
throws BeansException {
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext=
new AnnotationConfigApplicationContext();
MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor=
new MyBeanDefinitionRegistryPostProcessor();
applicationContext.addBeanFactoryPostProcessor(myBeanDefinitionRegistryPostProcessor);
applicationContext.refresh();
Student student=applicationContext.getBean(Student.class);
System.out.println(student);
}
}
学无止境,让学习成为一种习惯。
本人水平有限,有不对的地方请指教,谢谢。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)