Spring Series Part 5: Do you all know these ways to create bean instances?

Content of this article

  1. Create a bean object by calling the constructor through reflection

  2. Create bean objects through static factory methods

  3. Create bean objects through instance factory methods

  4. Create bean objects through FactoryBean

There are four common ways to create bean instance objects within the Spring container.

Create bean objects by calling the constructor through reflection

Calling the constructor method of a class to obtain the corresponding bean instance is the most commonly used method. This method only requires specifying the class attribute in the xml bean element. The spring container will automatically call the constructor method of this type to create the bean object and place it. in the container for use.

Grammar

<bean id="bean name" name="bean name or alias" class="bean's full type name">
    <constructor-arg index="0" value="bean value" ref="referenced bean name" />
    <constructor-arg index="1" value="bean value" ref="referenced bean name" />
    <constructor-arg index="2" value="bean value" ref="referenced bean name" />
    ....
    <constructor-arg index="n" value="bean value" ref="referenced bean name" />
</bean>

constructor-arg is used to specify the value of the constructor parameter

Index: The position of the parameter in the constructor, starting from 0 and increasing in sequence.

value: the value of the specified parameter

ref: When the inserted value is another bean in the container, this value is the name of the corresponding bean in the container.

Case

UserModel class
@Getter
@Setter
@ToString
public class UserModel {

    private String name;
    private int age;

    public UserModel() {
        this.name = "I created it through the parameterless constructor of UserModel!";
    }

    public UserModel(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
beans.xml configuration
<!-- Create a UserModel object through the default construction method of UserModel -->
<bean id="createBeanByConstructor1" class="com.javacode2018.lesson001.demo3.UserModel"/>

<!-- Create a UserModel object through the UserModel parameterized constructor -->
<bean id="createBeanByConstructor2" class="com.javacode2018.lesson001.demo3.UserModel">
    <constructor-arg index="0" value="I am an object constructed by the parameterized method of UserModel!"/>
    <constructor-arg index="1" value="30"/>
</bean>

For the above two writing methods, when the spring container creates these two UserModels, it will call the corresponding constructor in the UserModel class through reflection to create a UserModel object.

Test case
package com.javacode2018.lesson001.demo3;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;

/**
 * Public account: Passerby A Java, the former Ali P7 who has worked for 10 years shares Java, algorithms, and database technical dry goods! Firmly use technology to change destiny and let family members live a more decent life!
 */
public class Client {

    public static void main(String[] args) {
        //1.bean configuration file location
        String beanXml = "classpath:/com/javacode2018/lesson001/demo3/beans.xml";

        //2. Create a ClassPathXmlApplicationContext container and specify the bean configuration file to be loaded for the container
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);

        System.out.println("All beans in the spring container are as follows:");

        //getBeanDefinitionNames is used to get the names of all beans in the container
        for (String beanName : context. getBeanDefinitionNames()) {
            System.out.println(beanName + ":" + context.getBean(beanName));
        }

    }
}

The code will output the names of all beans in the spring container and their corresponding bean objects.

Run output
All beans in the spring container are as follows:
createBeanByConstructor1:UserModel(name=I created it through UserModel's no-argument construction method!, age=0)
createBeanByConstructor2:UserModel(name=I am an object constructed by the parameterized method of UserModel!, age=30)

Create bean objects through static factory methods

We can create a static factory, provide some static methods internally to generate the required objects, and hand over the objects created by these static methods to spring for use.

Grammar

<bean id="bean name" name="" class="full class name of static factory" factory-method="method of static factory">
    <constructor-arg index="0" value="bean value" ref="referenced bean name" />
    <constructor-arg index="1" value="bean value" ref="referenced bean name" />
    <constructor-arg index="2" value="bean value" ref="referenced bean name" />
    ....
    <constructor-arg index="n" value="bean value" ref="referenced bean name" />
</bean>

class: Specify the complete class name of the static factory

factory-method: A static method in a static factory that returns the required object.

constructor-arg is used to specify the value of the static method parameter, the usage is the same as the construction method introduced above.

The spring container will automatically call the static method of the static factory to obtain the specified object, and put it in the container for use.

Case

Define static factory

Create a static factory class for generating UserModel objects.

package com.javacode2018.lesson001.demo3;

/**
 * Public account: Passerby A Java, the former Ali P7 who has worked for 10 years shares Java, algorithms, and database technical dry goods! Firmly use technology to change destiny and let family members live a more decent life!
 */
public class UserStaticFactory {

    /**
     * Static parameterless method to create UserModel
     *
     * @return
     */
    public static UserModel buildUser1() {

        System.out.println(UserStaticFactory.class + ".buildUser1()");

        UserModel userModel = new UserModel();
        userModel.setName("I was created by a no-argument static constructor!");
        return userModel;
    }

    /**
     * Static parameterized method to create UserModel
     *
     * @param name name
     * @param age age
     * @return
     */
    public static UserModel buildUser2(String name, int age) {

        System.out.println(UserStaticFactory.class + ".buildUser2()");

        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setAge(age);
        return userModel;
    }
}
beans.xml configuration
<!-- Create a bean object through a factory static no-argument method -->
<bean id="createBeanByStaticFactoryMethod1" class="com.javacode2018.lesson001.demo3.UserStaticFactory"
      factory-method="buildUser1"/>

<!-- Create bean objects through factory static parameter methods -->
<bean id="createBeanByStaticFactoryMethod2" class="com.javacode2018.lesson001.demo3.UserStaticFactory"
      factory-method="buildUser2">
    <constructor-arg index="0" value="Create UerModel instance object through factory static parameter method"/>
    <constructor-arg index="1" value="30"/>
</bean>

In the above configuration, when the spring container starts, it will automatically call the buildUser1 static method in UserStaticFactory to obtain the UserModel object, and place it in the spring container as the bean object corresponding to the createBeanByStaticFactoryMethod1 name.

The buildUser2 method of UserStaticFactory will be called, and the two specified parameters will be passed in to get the returned UserModel object, which will be placed in the spring container as the bean object corresponding to the createBeanByStaticFactoryMethod2 name.

Run Client
class com.javacode2018.lesson001.demo3.UserStaticFactory.buildUser1()
class com.javacode2018.lesson001.demo3.UserStaticFactory.buildUser2()
All beans in the spring container are as follows:
createBeanByStaticFactoryMethod1:UserModel(name=I was created by the static constructor without parameters!, age=0)
createBeanByStaticFactoryMethod2:UserModel(name=Create UerModel instance object through factory static parameter method, age=30)

As can be seen from the output, both static methods have been called. The bean object corresponding to createBeanByStaticFactoryMethod1 is created through the buildUser1 method; the bean object corresponding to createBeanByStaticFactoryMethod2 is created through the buildUser2 method.

Create bean objects through instance factory methods

Let the spring container call certain instance methods of certain objects to generate bean objects and put them in the container for use.

Grammar

<bean id="bean name" factory-bean="The bean name of the instance object that needs to be called" factory-method="Method in the bean object">
    <constructor-arg index="0" value="bean value" ref="referenced bean name" />
    <constructor-arg index="1" value="bean value" ref="referenced bean name" />
    <constructor-arg index="2" value="bean value" ref="referenced bean name" />
    ....
    <constructor-arg index="n" value="bean value" ref="referenced bean name" />
</bean>

The spring container uses the value of factory-bean as the bean name to find the corresponding bean object, then calls the method specified by the factory-method attribute value in the object, and places the object returned by this method as the current bean object in the container for use.

Case

Define an instance factory

Write 2 methods internally to create UserModel objects.

package com.javacode2018.lesson001.demo3;

/**
 * Public account: Passerby A Java, the former Ali P7 who has worked for 10 years shares Java, algorithms, and database technical dry goods! Firmly use technology to change destiny and let family members live a more decent life!
 */
public class UserFactory {
    public UserModel buildUser1() {
        System.out.println("----------------------1");
        UserModel userModel = new UserModel();
        userModel.setName("The object created by the bean instance method!");
        return userModel;
    }

    public UserModel buildUser2(String name, int age) {
        System.out.println("----------------------2");
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setAge(age);
        return userModel;
    }
}
beans.xml
<!-- Define a factory instance -->
<bean id="userFactory" class="com.javacode2018.lesson001.demo3.UserFactory"/>
<!-- Create a UserModel object through the parameterless user method of the userFactory instance -->
<bean id="createBeanByBeanMethod1" factory-bean="userFactory" factory-method="buildUser1"/>

<!-- Create a UserModel object through the parameterized user method of the userFactory instance -->
<bean id="createBeanByBeanMethod2" factory-bean="userFactory" factory-method="buildUser2">
    <constructor-arg index="0" value="Create a UserModel instance object through a bean instance with a parameter method"/>
    <constructor-arg index="1" value="30"/>
</bean>

The bean corresponding to createBeanByBeanMethod1 is generated by the buildUser1 method of userFactory.

The bean corresponding to createBeanByBeanMethod2 is generated by the buildUser2 method of userFactory.

Run Client
All beans in the spring container are as follows:
createBeanByBeanMethod1:UserModel(name=object created by bean instance method!, age=0)
createBeanByBeanMethod2:UserModel(name=Create a UserModel instance object through a bean instance with a parameter method, age=30)

Create bean objects through FactoryBean

We have learned the BeanFactory interface before. BeanFactory is the top-level interface of the spring container. What we want to talk about here is FactoryBean, which is also an interface. These two interfaces are easy to confuse. FactoryBean allows the spring container to create us through the implementation of this interface. The required bean object.

FactoryBean interface source code:

public interface FactoryBean<T> {

    /**
     * Return the created object
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * Return the type of object to be created
     */
    @Nullable
    Class<?> getObjectType();

    /**
    * Whether the bean is a singleton
    **/
    default boolean isSingleton() {
        return true;
    }

}

There are three methods in the interface. The first two methods need to be implemented by us. Inside the getObject method, the developer creates the object himself, and then returns the created object to the Spring container. getObjectType needs to specify the type of bean we create; The last method isSingleton indicates whether the object created through this interface is a singleton. If it returns false, then getObject() of this interface will be called every time an object is obtained from the container to generate a bean object.

Grammar

<bean id="bean name" class="FactoryBean interface implementation class" />

Case

Create a FactoryBean implementation class
package com.javacode2018.lesson001.demo3;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;

/**
 * Public account: Passerby A Java, the former Ali P7 who has worked for 10 years shares Java, algorithms, and database technical dry goods! Firmly use technology to change destiny and let family members live a more decent life!
 */
public class UserFactoryBean implements FactoryBean<UserModel> {
    int count = 1;
    @Nullable
    @Override
    public UserModel getObject() throws Exception { //@1
        UserModel userModel = new UserModel();
        userModel.setName("I created the first " + count + + + "object" through FactoryBean");//@4
        return userModel;
    }

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

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

@1: Returns a created UserModel object

@2: Return the Class object of the object

@3: Return true, indicating that the created object is a singleton, then every time we get this object from the container, it is the same object

@4: A count is used here. Through this, you can see whether the beans obtained from the container are the same when isSingleton returns different values.

bean xml configuration
<!-- Create UserModel object through FactoryBean -->
<bean id="createByFactoryBean" class="com.javacode2018.lesson001.demo3.UserFactoryBean"/>
Client code
package com.javacode2018.lesson001.demo3;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;

/**
 * Public account: Passerby A Java, the former Ali P7 who has worked for 10 years shares Java, algorithms, and database technical dry goods! Firmly use technology to change destiny and let family members live a more decent life!
 */
public class Client {

    public static void main(String[] args) {
        //1.bean configuration file location
        String beanXml = "classpath:/com/javacode2018/lesson001/demo3/beans.xml";

        //2. Create a ClassPathXmlApplicationContext container and specify the bean configuration file to be loaded for the container
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);

        System.out.println("All beans in the spring container are as follows:");

        //getBeanDefinitionNames is used to get the names of all beans in the container
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName + ":" + context.getBean(beanName));
        }

        System.out.println("--------------------------");
        //Get createByFactoryBean multiple times to see if it is the same object
        System.out.println("createByFactoryBean:" + context.getBean("createByFactoryBean"));
        System.out.println("createByFactoryBean:" + context.getBean("createByFactoryBean"));
    }
}

Run output

class com.javacode2018.lesson001.demo3.UserStaticFactory.buildUser1()
class com.javacode2018.lesson001.demo3.UserStaticFactory.buildUser2()
----------------------1
----------------------2
All beans in the spring container are as follows:
createBeanByConstructor1:UserModel(name=I created it through the parameterless constructor of UserModel!, age=0)
createBeanByConstructor2:UserModel(name=I am an object constructed through the parameterized method of UserModel!, age=30)
createBeanByStaticFactoryMethod1:UserModel(name=I was created by the static constructor without parameters!, age=0)
createBeanByStaticFactoryMethod2:UserModel(name=Create UerModel instance object through factory static parameter method, age=30)
userFactory:com.javacode2018.lesson001.demo3.UserFactory@610694f1
createBeanByBeanMethod1:UserModel(name=object created by bean instance method!, age=0)
createBeanByBeanMethod2:UserModel(name=Create a UserModel instance object through the bean instance parameter method, age=30)
createByFactoryBean:UserModel(name=I am the first object created through FactoryBean, age=0)
--------------------------
createByFactoryBean:UserModel(name=I am the first object created through FactoryBean, age=0)
createByFactoryBean:UserModel(name=I am the first object created through FactoryBean, age=0)

Pay attention to the last four lines of output. Three of them output the same createByFactoryBean. In the program, createByFactoryBean is searched from the spring container through getBean three times. The results are the same three times, indicating that the same UserModel object is returned.

Next we adjust isSingleton in UserFactoryBean and return false

@Override
public boolean isSingleton() {
    return false;
}

When this method returns false, it means that the object created by this FactoryBean has multiple instances. Then every time we getBean from the container, we will re-call the getObject method in FactoryBean to obtain a new object.

Run the Client again, and output the last 4 lines:

createByFactoryBean:UserModel(name=I am the first object created through FactoryBean, age=0)
--------------------------
createByFactoryBean:UserModel(name=I am the second object created through FactoryBean, age=0)
createByFactoryBean:UserModel(name=I am the third object created through FactoryBean, age=0)

The objects obtained these 3 times are different.

Summary

The spring container provides 4 ways to create bean instances. In addition to the constructor method, there are several other ways that allow us to manually control the creation of objects. Everyone has mastered these methods and can use them flexibly.

Case code

Link: https://pan.baidu.com/s/1p6rcfKOeWQIVkuhVybzZmQ
Extraction code: zr99