4 ways for IOC containers to create bean instances

Personal public account: 😕 Can be programmed?
Personal Creed: Be content with what you are satisfied with and know what you are not enough to do. Do something or not do something. Both doing and not doing are acceptable
Introduction to this article: This article records 4 ways for IOC containers to create bean instances. Please correct me if there are any discrepancies.

Follow the official account [Can Program] and reply [Interview] to receive the latest interview questions of the year!!!

Now that we understand what IOC is, let’s see what the IOC container can do. First of all, its most important function is to manage and create beans. There are four ways for the IOC container to create bean instances, as follows:

  1. Create bean objects 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. These four can be divided into two major types. One is based on reflection mechanism, and the other is based on factory mode. Based on this and combined with cases, I will explain the two in depth. Differences and principles.

1. Create a bean object 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 a container for use.

If you use annotations to create and manage beans, you also use the reflection mechanism. With the development of Spring, annotations have gradually become the mainstream configuration method. Using annotations can reduce the amount of code in the configuration file and put related configuration information and code together, improving maintainability. For example, beans can be automatically created using @Component, @Service, @Repository, @Controller and other annotations.

Follow the official account [Can Program] and reply [Interview] to receive the latest collection of interview questions of the year!!!

<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="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.

For example: I use two methods here. First, use the Xml configuration file to configure and define the Bean. The second is to use the annotation form to generate the Bean.

2. IOC container initialization details

Person class
public class Person {

    public String name;
    public Integer age;
    Wife wife;

    public Person(String s, Integer s2, Wife wife) {
        System.out.println("Reflection creates instances by calling constructors...");
        this.name = s;
        this.age = s2;
        this.wife = wife;
    }
...Omit the get() set() method of the attribute
}

beans.xml configuration

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        ">

    <!--Add a wife object in the construction method-->
    <bean class="org.kewei.pojo.Person" id="person">
        <constructor-arg type="org.kewei.pojo.Wife" ref="wife"/>
        <constructor-arg index="0" value="Can be programmed" />
        <constructor-arg index="1" value="18" />
    </bean>
    <bean class="org.kewei.pojo.Wife" id="wife" autowire-candidate="true">
        <property name="age" value="18"/>
        <property name="name" value="can be"/>
    </bean>

</beans>

When the spring container creates a Person, it will call the corresponding constructor in the Person class through reflection to create a Person object.

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("test.xml");
        Person person = (Person) classPathXmlApplicationContext.getBean("person");
        System.out.println(person.name + person.age);
        System.out.println(person.getWifeName() + person.getWifeAge());
    }
}

Use the @Service annotation to define a Bean. If the BeanId is not specified, the system will automatically generate the Bean name with the first letter of the class name in lowercase.

@Service
public class KeWeiService {
    public KeWeiService() {

        System.out.println("Creating KeWeiService based on annotation form--- " + this);
        System.out.println("Reflection creates instances by calling constructors...--- " + this);
    }
}
//Get Bean
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(KeWeiService.class);
        KeWeiService kw = (KeWeiService) annotationConfigApplicationContext.getBean("keWeiService");
        System.out.println(kw);
    }
}

The test results are shown below. It can be seen that the reflection mechanism is used to generate and create beans. It’s just two different methods. In principle, they are still based on Java’s reflection principle.

Picture

The Spring framework uses the Java reflection (Reflection) mechanism when creating beans. This mechanism allows Spring to inspect and modify some of the object’s behavior at runtime. For example, AOP uses a reflection mechanism to modify the behavior of beans at runtime, such as aspects, which can intercept method calls of the target object and add additional logic processing before and after the call. Spring uses reflection to obtain the target method. information and dynamically weave in additional code logic. It is true that dynamic proxy technology is also used here.

Follow the official account [Can Program] and reply [Interview] to receive the latest collection of interview questions of the year!!!

In summary, the Spring container uses reflection to instantiate, configure and manage beans. When the Spring container starts, it reads configuration files (such as XML or Java class annotations) and creates Bean instances based on this configuration information. In this process, Spring uses reflection to call the constructor or static method of the object to create the Bean. For properties, Spring also uses reflection to set the properties of the Bean. When a Bean property is defined in the configuration file, Spring will use reflection. Call the object’s setter method to set the property values of these beans. In fact, reflection is reflected in many places in Spring. Using the Java reflection mechanism, Spring implements core functions such as lazy loading, dependency injection, and AOP.

2. Create Bean objects through static factory methods

We can also use the factory pattern to 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 subsequent use.

<bean id="bean name" name="" class="Static factory full class name" factory-method="Static factory method">
    <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="n" value="bean value" ref="referenced bean name" />
</bean>

class: Specify the complete class name of the static factory

factory-method: Static method in static factory, returns the required object.

constructor-arg is used to specify the value of static method parameters, and its usage is the same as the constructor method introduced above.

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

Define static factory

Create a static factory class to generate Person objects.

public class PersonStaticFactory {

    /**
     * Static parameterless method to create Person
     *
     * @return
     */
    public static Person build() {
        System.out.println(PersonStaticFactory.class + ".buildPerson1()");
        Person person = new Person();
        person.setName("I was created by the static constructor without parameters!");
        return person;
    }

    /**
     * Static parameterized method to create Person
     *
     * @param name name
     * @param age age
     * @return
     */
    public static Person build2(String name, int age) {
        System.out.println(PersonStaticFactory.class + ".buildPerson2()");
        Person person2 = new Person();
        person2.setName(name);
        person2.setAge(age);
        return person2;
    }
}
beans.xml configuration
<!-- Create bean objects through factory static parameterless methods -->
<bean id="createBeanByStaticFactoryMethod1" class="org.kewei.service.PersonStaticFactory"
factory-method="build"/>
<!-- Create bean objects through factory static parameter methods -->
<bean id="createBeanByStaticFactoryMethod2" class="org.kewei.service.PersonStaticFactory"
factory-method="build2">
   <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 build() static method in PersonStaticFactory to obtain the Person object, and place it in the IOC container as the bean object corresponding to the createBeanByStaticFactoryMethod1 name.

Call the build2() method of PersonStaticFactory and pass in the two specified parameters to get the returned Person object and place it in the IOC container as the bean object corresponding to the createBeanByStaticFactoryMethod2 name.

ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("test.xml");
Person createBeanByStaticFactoryMethod1 = (Person) classPathXmlApplicationContext.getBean("createBeanByStaticFactoryMethod1");
Person createBeanByStaticFactoryMethod2 = (Person) classPathXmlApplicationContext.getBean("createBeanByStaticFactoryMethod2");
System.out.println(createBeanByStaticFactoryMethod1.name + createBeanByStaticFactoryMethod1.age);
System.out.println(createBeanByStaticFactoryMethod2.name + createBeanByStaticFactoryMethod2.age);
---------------------------------------------
I was created using a parameterless static constructor! null
Create Person instance object 30 through factory static parameter method

It can be seen from the output that both static methods have been called and both output corresponding information. The first line is the Bean generated by the build() method, and the second line is the Bean object generated by the build2() method.

The above is to obtain the Bean object through the configuration file. Next, I will demonstrate how to generate the Bean object through the static factory through annotation.

Follow the official account [Can Program] and reply [Interview] to receive the latest collection of interview questions of the year!!!

Annotation configuration

Of course, if the method is static, we can call it directly, but in order to demonstrate the role of annotations, we leave it to Spring for management, so we obtain the Bean object by adding annotations.

@Configuration
public class PersonStaticFactory {

    /**
     * Static parameterless method to create Person
     *
     * @return
     */
    @Bean("createBeanByStaticFactoryMethod1")
    public static Person build() {
        System.out.println(PersonStaticFactory.class + ".buildPerson1()");
        Person person = new Person();
        person.setName("I was created by the static constructor without parameters!");
        return person;
    }

    /**
     * Static parameterized method to create Person
     *
     * @return
     */
    @Bean("createBeanByStaticFactoryMethod2")
    public static Person build2() {
        System.out.println(PersonStaticFactory.class + ".buildPerson2()");
        Person person2 = new Person();
        person2.setName("Created through factory static parameter method");
        person2.setAge(18);
        return person2;
    }
}

Create a Bean using a static method through the @Bean annotation and get it by the name of the bean (createBeanByStaticFactoryMethod1 in this case). First, ensure that the configuration class is scanned by Spring and uses the @Configuration annotation to mark the configuration class. To obtain a bean directly by name in a non-Spring managed class, you need to manually obtain it from the Spring context AnnotationConfigApplicationContext.

AnnotationConfigApplicationContext annotationConfigApplicationContext1 = new AnnotationConfigApplicationContext(PersonStaticFactory.class);
Person createBeanByStaticFactoryMethod1 = (Person) annotationConfigApplicationContext1.getBean("createBeanByStaticFactoryMethod1");
Person createBeanByStaticFactoryMethod2 = (Person) annotationConfigApplicationContext1.getBean("createBeanByStaticFactoryMethod2");
System.out.println(createBeanByStaticFactoryMethod1.name + createBeanByStaticFactoryMethod1.age);
System.out.println(createBeanByStaticFactoryMethod2.name + createBeanByStaticFactoryMethod2.age);

Obviously, there is a lot less code than the way we use Xml configuration. This is also the mainstream method that Spring will implement later.

3. 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.

<bean id="bean name" factory-bean="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="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.

Define an instance factory

Two methods are written internally to create Person objects.

public class PersonFactory {

    /**
     * Static parameterless method to create Person
     *
     * @return
     */
    public Person build() {
        System.out.println(PersonFactory.class + ".buildPerson1()");
        Person person = new Person();
        person.setName("I was created by the static constructor without parameters!");
        return person;
    }

    /**
     * Static parameterized method to create Person
     * Follow the public account [Can Program] and reply to [Interview] to get the latest interview questions of the year!!!
     *
     * @return
     */
    public Person build2(String name, int age) {
        System.out.println(PersonFactory.class + ".buildPerson2()");
        Person person2 = new Person();
        person2.setName(name);
        person2.setAge(age);
        return person2;
    }
}
beans.xml configuration
 <!-- Define a factory instance -->
  <bean id="personFactory" class="org.kewei.service.PersonFactory"/>
  <!-- Create a UserModel object through the parameterless user method of the userFactory instance -->
  <bean id="createBeanByBeanMethod1" factory-bean="personFactory" factory-method="build"/>
  <!-- Create a UserModel object through the parameterized user method of the userFactory instance -->
  <bean id="createBeanByBeanMethod2" factory-bean="personFactory" factory-method="build2">
      <constructor-arg index="0" value="Create a UserModel instance object through the bean instance parameter method"/>
      <constructor-arg index="1" value="30"/>
  </bean>

The bean corresponding to createBeanByBeanMethod1 is generated through the build method of personFactory.

The bean corresponding to createBeanByBeanMethod2 is generated through the build2 method of personFactory.

ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("test.xml");
Person createBeanByStaticFactoryMethod1 = (Person) classPathXmlApplicationContext.getBean("createBeanByBeanMethod1");
Person createBeanByStaticFactoryMethod2 = (Person) classPathXmlApplicationContext.getBean("createBeanByBeanMethod2");
System.out.println(createBeanByStaticFactoryMethod1.name + createBeanByStaticFactoryMethod1.age);
System.out.println(createBeanByStaticFactoryMethod2.name + createBeanByStaticFactoryMethod2.age);
---------------------------------------------
I was created using a parameterless static constructor! null
Create UserModel instance object through bean instance parameter method 30

Similarly we can change it to the form of annotation

Annotation configuration
@Service
public class PersonFactory {

    /**
     * Static parameterless method to create Person
     *
     * @return
     */
    public Person build() {
        System.out.println(PersonFactory.class + ".buildPerson1()");
        Person person = new Person();
        person.setName("I was created by the static constructor without parameters!");
        return person;
    }

    /**
     * Static parameterized method to create Person
     *
     * @return
     */
    public Person build2(String name, int age) {
        System.out.println(PersonFactory.class + ".buildPerson2()");
        Person person2 = new Person();
        person2.setName(name);
        person2.setAge(age);
        return person2;
    }
}

We only need to add a @Service annotation on it to directly call the methods inside.

 AnnotationConfigApplicationContext annotationConfigApplicationContext1 = new AnnotationConfigApplicationContext(PersonFactory.class);
 PersonFactory personFactory = (PersonFactory) annotationConfigApplicationContext1.getBean("personFactory");
 System.out.println(personFactory.build().name);
---------------------------------------------
class org.kewei.service.PersonFactory.buildPerson1()
I was created using a parameterless static construction method!

4. 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.

Follow the official account [Can Program] and reply [Interview] to receive the latest collection of interview questions of the year!!!

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.

<bean id="bean name" class="FactoryBean interface implementation class" />
Create a FactoryBean implementation class?
public class PersonFactoryBean implements FactoryBean<Person> {
    int count = 1;

    @Nullable
    @Override
    public Person getObject() { //1
        Person person = new Person();
        person.setName("I was created through FactoryBean" + count + + + "object");//4
        return person;
    }

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

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

//1: Returns a created Person object.

//2: Return the Class object of the object.

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

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

bean xml configuration
<!-- Create Person object through FactoryBean -->

<bean id="createByFactoryBean" class="org.kewei.service.PersonFactoryBean"/>

Add the following code to the startup class:

System.out.println("-------------The following are the Bean objects created by FactoryBean-------------");
//1.bean configuration file location
String beanXml = "classpath:/test.xml";
//2. Create a ClassPathXmlApplicationContext container and specify the bean configuration file that needs to be loaded in 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
//Follow the public account [Can be programmed] and reply to [Interview] to receive the latest collection of interview questions of the year!!!
for (String beanName : context.getBeanDefinitionNames()) {
     System.out.println(beanName + ":" + context.getBean(beanName));
}
//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"));

Picture

Pay attention to the last three lines of output. The output is the same createByFactoryBean, and the object is unique. In the program, createByFactoryBean is searched from the IOC container through getBean three times. The results of the three times are the same object, indicating that the same Person 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, and then run the Client. The last 3 lines of output:

Picture

Obviously, the objects obtained these three times are different, which is also the scope of SpringBean. The next article will explain the scope of SpringBean.

Summary

The SpringIOC container provides 4 ways to create bean instances. In addition to the constructor method, several other ways allow us to manually control the creation of objects. Everyone has mastered these methods and can use them flexibly. If you need the source code, contact me to get it.

Picture

Analyze the whole process of Spring-IOC container from the outside to the inside

Core concepts in Spring

Don’t call it a comeback: Why Java is still the champ!

Several concepts you must know about high concurrency

Comparison of thread creation methods and analysis of thread pool related principles

Summary of daily use of BigDecimal objects

Picture

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 139030 people are learning the system