1. 程式人生 > >Spring 學習一 bean 注入方式

Spring 學習一 bean 注入方式

Bean 的注入方式

介紹向 IOC 容器注入 bean 的方式

  • XML 配置的方式

public class Person {
    private String name;
    private Integer age;
}

xml 檔案的配置

	<bean id="person" class="com.john.bean.Person">
		<property name="name" value="lisi" />
		<property name="age" value="19" />
	</bean>
    @Test
    public void person01() {
        Resource resource = new ClassPathResource("bean.xml");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(resource);
        Person bean = (Person ) factory.getBean("persion");
        System.out.println(bean);
    }
  • 註解配置的方式 @Bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.john.bean.Person;

/**
 * 配置類,在這裡可以配置需要的 Bean
 */
@Configuration
public class BeanConfig {

    /**
     * 添加註解 @Bean 表示向 IOC 容器注入一個 bean
     * Bean 的 id 有 @Bean 的 name 屬性指定
     * 如果沒有指定,則預設是方法名 
     */
    @Bean
    public Person person() {
        return new Person("liLian", 34);
    }
    
    // @Bean value 和 name 是一樣的,兩個註解屬性,同時只能存在一個
    @Bean(name = "instance")
    public Person createInstance() {
        return new Person("劉以鬯", 29);
    }
}
    @Test
    public void person02() {
        ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
        // 獲取 IOC 容器中所有的 bean 的名稱
        String[] names = context.getBeanDefinitionNames();
        Arrays.asList(names).stream().forEach(System.out::println);
        
        System.out.println("------------------------------");
        // 根據 id 獲取 bean
        Person person = (Person) context.getBean("person");
        System.out.println(person);
        
        System.out.println("------------------------------");
        // 根據 bean 的型別獲取 bean
        Person person2 = context.getBean("instance", Person.class);
        System.out.println(person2);
    }

測試結果

  • 匯入元件 @Import

原始碼

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
	 * or regular component classes to import.
	 */
	Class<?>[] value();

}

使用

@Configuration
@Import(value = Student.class) // 需要匯入到 IOC 容器中的元件
public class MainConfig {
}
  • 匯入選擇器 ImportSelector

原始碼

public interface ImportSelector {

	/**
	 * Select and return the names of which class(es) should be imported based on
	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

}

使用:實現 ImportSelector 介面

public class MyImportSelector implements ImportSelector {

    /** 返回需要匯入的元件全類名稱  */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {"com.john.bean.Perjoce","com.john.bean.Teacher"};
    }

}

  • 通過FactoryBean 注入元件

原始碼

public interface FactoryBean<T> {

	/** 獲取需要注入到 IOC 容器的 bean 元件 */
	@Nullable
	T getObject() throws Exception;

	/** 獲取 IOC 容器中 bean 元件的型別	 */
	@Nullable
	Class<?> getObjectType();

	/** bean 元件是否是單例	 */
	default boolean isSingleton() {
		return true;
	}

}

使用:實現 FactoryBean 介面,泛型 是要注入到 IOC 容器中的型別

public class CatBean implements FactoryBean<CatEntity> {

    @Override
    public CatEntity getObject() throws Exception {
        return new CatEntity();
    }

    @Override
    public Class<?> getObjectType() {
        return CatEntity.class;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }

}

注入 factoryBean

@Configuration
public class MainConfig {

    @Bean(value = "catEntity")
    public CatBean getEntity() {
        return new CatBean();
    }
}
public class CatBeanTest {

    @Test
    public void catEntityTest() {
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
       CatEntity bean = (CatEntity) context.getBean("catEntity");
       System.out.println(bean);
    }

}

測試結果,獲取的是 CatEntity 例項,而不是 CatBean 的例項,說明我們通過實現 FactoryBean 介面注入到 IOC 容器中的是一個 bean 例項,而並不是 FactoryBean 的例項
在這裡插入圖片描述
如果需要獲取 FactoryBean 例項本身,只需要在獲取 bean 例項時,在前面加 ‘&’ 字元即可

public class CatBeanTest {

    @Test
    public void catEntityTest() {
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
       CatEntity bean = (CatEntity) context.getBean("catEntity");
       System.out.println(bean);
       
      CatBean bean2 = (CatBean) context.getBean("&catEntity");
      System.out.println(bean2);
    }

}

在這裡插入圖片描述
原因可以看 BeanFactory 介面,下面是 BeanFactory 部分原始碼

public interface BeanFactory {

	/**
	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
	 * will return the factory, not the instance returned by the factory.
	 */
	String FACTORY_BEAN_PREFIX = "&";
}