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

猜你喜欢

转载自blog.csdn.net/qq_22925909/article/details/84900279