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 = "&";
}