Spring 學習一 bean 注入方式
阿新 • • 發佈:2018-12-22
Bean 的注入方式
介紹向 IOC 容器注入 bean 的方式
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); }
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);
}
原始碼
@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 {
}
原始碼
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"};
}
}
原始碼
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 = "&";
}