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

學無止境,讓學習成為一種習慣。

本人水平有限,有不對的地方請指教,謝謝。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM