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);
  }
}

学无止境,让学习成为一种习惯。

本人水平有限,有不对的地方请指教,谢谢。

 

posted @   霞宝的油腻大叔  阅读(934)  评论(0编辑  收藏  举报
编辑推荐:
· 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)
点击右上角即可分享
微信分享提示