Spring创建bean实例的常用四种方式

Spring创建bean实例的常用方式

  • 一、通过反射调用构造方法创建bean对象
  • 二、通过静态工厂方法创建bean对象
  • 三、通过实例工厂方法创建bean对象
  • 四、通过factoryBean创建bean对象

Spring创建bean实质是:通过一个类的全限定类型用反射去创建对象,最后放入一个Map集合中,需要使用某个bean的话可以用id类查找。

1、创建一个properties文件,列出需要创建的对象的全限定类型

userService=com.zjhc.beanByHand.UserService
bookService=com.zjhc.beanByHand.BookService

2、创建一个bean工厂类,来通过反射创建对象

public class BeanFactory {
    //定义一个静态的配置文件对象
    private static Properties props;
    //定义一个存放对象的Map容器
    private static Map<String,Object> beans;

    //通过静态块给props赋值
    static{
        try {
            //实例化props对象
            props = new Properties();
            //通过类加载器获取加载配置文件的流,并且将文件加到输入流
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            //加载bean配置文件
            props.load(in);
            //实例化容器
            beans = new HashMap<String, Object>();
            //取出配置文件种所有的key
            Enumeration keys = props.keys();
            while(keys.hasMoreElements()){
                //取出每个key
                String key = keys.nextElement().toString();
                //根据key获取value
                String beanPath = props.getProperty(key);
                //反射创建对象
                Object value = Class.forName(beanPath).newInstance();
                //将创建好的对象放入容器
                beans.put(key,value);
            }
        } catch (Exception e) {
            throw new ExceptionInInitializerError("配置文件初始化创建对象异常....");
        }
    }

    //根据bean的名称获取对象
    public static Object getBean(String beanName){
        return beans.get(beanName);
    }
}

测试:

public class UserService {
    public static void main(String[] args) {
        BookService bookService = (BookService) BeanFactory.getBean("bookService");
        System.out.println(bookService);
    }
}
public class BookService {
    public static void main(String[] args) {
        UserService userService = (UserService) BeanFactory.getBean("userService");
        System.out.println(userService);
    }
}

结果:

com.zjhc.beanByHand.UserService@7440e464
com.zjhc.beanByHand.BookService@7440e464

一、通过反射调用构造方法创建bean对象

调用类的构造方法获取对应的bean实例,是使用最多的方式,这种方式只需要在xml的bean元素中指定class属性,spring容器内部会自动调用该类型的构造方法来创建bean对象,将其放在容器中以供使用

  1. 语法:
<bean id="bean名称" name="bean名称或者别名" class="bean的完整类型名称">
    <constructor-arg index="0" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="1" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="2" value="bean的值" ref="引用的bean名称" />
    ....
    <constructor-arg index="n" value="bean的值" ref="引用的bean名称" />
bean>
  • constructor-arg用于指定构造方法参数的值
  • index:构造方法中参数的位置,从0开始,依次递增
  • value:指定参数的值
  • ref:当插入的值为容器内其他bean的时候,这个值为容器中对应bean的名称
  1. UserModel类
@Data
public class UserModel {

    private String name;
    private int age;

    public UserModel(){
        this.name = "我是通过反射调用UserModel的无参构造创建的";
    }

    public UserModel(String name,int age){
        this.name = name;
        this.age = age;
    }
}
  1. beans.xml
 
    <bean id="userModel1" class="com.zjhc.model.UserModel"/>

    
    <bean id="userModel2" class="com.zjhc.model.UserModel">
        <constructor-arg index="0" value="我是通过反射调用UserModel有参构造创建的"/>
        <constructor-arg index="1" value="11"/>
    bean>
  1. 测试
@Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName+" : "+context.getBean(beanName));
        }
    }
  1. 结果
    Spring创建bean实例的常用四种方式_第1张图片

二、通过静态工厂方法创建bean对象

我们可以创建静态工厂,内部提供一些静态方法来生成所需要的对象,将这些静态方法创建的对象交给spring以供使用

  1. 语法
<bean id="bean名称" name="" class="静态工厂完整类名" factory-method="静态工厂的方法">
    <constructor-arg index="0" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="1" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="2" value="bean的值" ref="引用的bean名称" />
    ....
    <constructor-arg index="n" value="bean的值" ref="引用的bean名称" />
</bean>
  1. 创建静态工厂
public class UserModelStaticFactory {

    /**
     * 静态无参方法创建Usermodel
     * @return
     */
    public static UserModel builder1(){
        System.out.println(UserModel.class+".builder1()");
        UserModel userModel = new UserModel();
        userModel.setName("我是通过静态的UserModel无参方法创建的");
        return userModel;
    }

    /**
     * 静态有参方法创建Usermodel
     * @return
     */
    public static UserModel builder2(String name,int age){
        System.out.println(UserModel.class+".builder2()");
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setAge(age);
        return userModel;
    }
}
  1. beans.xml
  
    <bean id="ceateBeanByStaticFactory1" class="com.zjhc.model.UserModelStaticFactory" factory-method="builder1"/>

    
    <bean id="createBeanByStaticFactory2" class="com.zjhc.model.UserModelStaticFactory" factory-method="builder2">
        <constructor-arg index="0" value="我是通过静态的UserModel有参方法创建的"/>
        <constructor-arg index="1" value="27"/>
    bean>
  1. 测试
 @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("spring容器中所有bean如下:");
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName+" : "+context.getBean(beanName));
        }
    }

5.结果
Spring创建bean实例的常用四种方式_第2张图片

三、通过实例工厂方法创建bean对象

让spring容器去调用某些对象的某些实例方法来生成bean对象放在容器中以供使用

  1. 语法
<bean id="bean名称" factory-bean="需要调用的实例对象bean名称" factory-method="bean对象中的方法">
    <constructor-arg index="0" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="1" value="bean的值" ref="引用的bean名称" />
    <constructor-arg index="2" value="bean的值" ref="引用的bean名称" />
    ....
    <constructor-arg index="n" value="bean的值" ref="引用的bean名称" />
bean>
  1. 创建实例工厂
public class CreateBeanByBeanInstanceFactory {

    public UserModel builder1(){
        UserModel userModel = new UserModel();
        userModel.setName("我是通过实例工厂的无参方法创建的");
        return userModel;
    }

    public UserModel builder2(String name,int age){
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setAge(age);
        return userModel;
    }
}
  1. beans.xml

<bean id="beanInstanceFactory" class="com.zjhc.model.CreateBeanByBeanInstanceFactory"/>

<bean id="createBeanByBeabInstance1" factory-bean="beanInstanceFactory" factory-method="builder1"/>

<bean id="createBeanByBeabInstance2" factory-bean="beanInstanceFactory" factory-method="builder2">
   <constructor-arg index="0" value="我是通过实例工厂的有参方法创建的"/>
   <constructor-arg index="1" value="28"/>
bean>
  1. 测试
@Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("spring容器中所有bean如下:");
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName+" : "+context.getBean(beanName));
        }
    }
  1. 结果
    Spring创建bean实例的常用四种方式_第3张图片

四、通过factoryBean创建bean对象

FactoryBean接口可以让spring容器通过这个接口的实现来创建我们需要的bean对象

  1. 接口源码
public interface FactoryBean<T> {

    /**
     * 返回创建好的对象
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * 返回需要创建的对象的类型
     */
    @Nullable
    Class<?> getObjectType();

    /**
    * bean是否是单例的
    **/
    default boolean isSingleton() {
        return true;
    }
}

接口中有3个方法,前面2个方法需要我们去实现,getObject方法内部由开发者自己去实现对象的创建,然后将创建好的对象返回给Spring容器,getObjectType需要指定我们创建的bean的类型;最后一个方法isSingleton表示通过这个接口创建的对象是否是单例的,如果返回false,那么每次从容器中获取对象的时候都会调用这个接口的getObject() 去生成bean对象。

  1. 创建FactoryBean实现类
public class CreateBeanByFactoryBean implements FactoryBean<UserModel> {
    private int count = 1;

    @Nullable
    @Override
    public UserModel getObject() throws Exception {  //1
        UserModel userModel = new UserModel();
        userModel.setName("我是通过FactoryBean创建的第"+count+++ "对象");  //4
        userModel.setAge(29);
        return userModel;
    }

    @Nullable
    @Override
    public Class<?> getObjectType() {
        return UserModel.class;  //2
    }

    @Override
    public boolean isSingleton() {  //3
        return true;
    }
}

step1:返回了一个创建好的UserModel对象

step2:返回对象的Class对象

step3:返回true,表示创建的对象是单例的,那么我们每次从容器中获取这个对象的时候都是同一个对象

step4:此处用到了一个count,通过这个一会可以看出isSingleton不同返回值的时候从容器获取的bean是否是同一个
3. beans.xml


    <bean id="createBeanByFactoryBean" class="com.zjhc.model.CreateBeanByFactoryBean"/>
  1. 测试
  @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("spring容器中所有bean如下:");
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName+" : "+context.getBean(beanName));
        }
        System.out.println("=======================================================");
        System.out.println("createBeanByFactoryBean:"+context.getBean("createBeanByFactoryBean"));
        System.out.println("createBeanByFactoryBean:"+context.getBean("createBeanByFactoryBean"));
    }
  1. 结果
    Spring创建bean实例的常用四种方式_第4张图片
    注意最后4行输出,有3行输出的都是同一个createByFactoryBean,程序中通过getBean从spring容器中查找createByFactoryBean了3次,3次结果都是一样的,说明返回的都是同一个UserModel对象
  2. 测试非单例模式
    当这个方法返回false的时候,表示由这个FactoryBean创建的对象是多例的,那么我们每次从容器中getBean的时候都会去重新调用FactoryBean中的getObject方法获取一个新的对象。
    @Override
    public boolean isSingleton() {  //3
        return false;
    }
  1. 结果
    Spring创建bean实例的常用四种方式_第5张图片

你可能感兴趣的:(spring,spring,java)