Four ways for IOC container to create bean objects

Keywords: Java Spring Container

preface:

  • The Spring container creates a bean object. Generally, it finds the class to be instantiated by looking up the class attribute value of the bean element through the reflection mechanism, so as to instantiate the bean object. This is to call the constructor to instantiate the bean object

  • In some cases, a simple xml configuration file, such as writing a large number of bean elements, will greatly increase the workload. The Spring container also adds some attributes of bean elements to reduce the workload of writing configuration files. For example, static factory method (factory method attribute), instance factory method (factory bean attribute, factory method attribute)

  • In addition, Spring also provides a FactoryBean interface to support developers to customize the way to instantiate bean objects

1. Call the constructor to create a bean object

  • Explanation:

    • Call the constructor of the class to get the corresponding bean instance
    • In the configuration file, just set the class attribute of the bean element, and the Spring container will automatically call the constructor to create the bean object
  • Basic format:

    <bean id="bean name" name="bean Name or alias" class="Full classpath">
        <constructor-arg index="0" value="bean Value of" ref="Referenced bean name" />
        <constructor-arg index="1" value="bean Value of" ref="Referenced bean name" />
        ....
    </bean>
    
    • Constructor Arg: used to specify the value of the constructor parameter
      • index: the position of the parameter in the construction method, starting from 0 and increasing in turn
      • value:
        • Set values for construction parameters. The types of values can only be simple types, such as byte,int,long,float,double,boolean,Byte,Long,Float,Double, enumeration, etc;
        • When the Spring container injects attributes, it will automatically convert the value value to the corresponding type
      • ref: when the inserted value is other beans in the container, this value is the name of the corresponding bean in the container
    • If constructor arg is not specified, the Spring container will call the default parameterless constructor method to create the bean object; If constructor arg is specified, parameterized constructor method is called to create bean object
    • If constructor arg is specified, index must correspond to attributes of the entity class one by one
  • case

    • Entity class

      package com.spring.study;
      
      public class Dog {
      
          private String name;
          private int age;
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          public Dog() {
              this.name = "Xiaobai";
              this.age = 1;
          }
      
          public Dog(String name, int age) {
              this.name = name;
              this.age = age;
          }
      }
      
    • configuration file

      <?xml version="1.0" encoding="UTF-8"?>
      <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 http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--    The default is to call the parameterless construction method to create bean object-->
          <bean id="dog1" class="com.spring.study.Dog"/>
      
          <!--    Call the parameterized constructor method to create bean object-->
          <bean id="dog2" class="com.spring.study.Dog">
              <constructor-arg index="0" value="chinese rhubarb"/>
              <constructor-arg index="1" value="2"/>
          </bean>
      </beans>
      
    • Test class

      package com.spring.test;
      
      import com.spring.study.Dog;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestConstructor {
          public static void main(String[] args) {
              // 1. Define bean configuration file location
              String classPathXml = "classpath:applicationContext.xml";
      
              // 2. Create a ClassPathXmlApplicationContext container and specify the bean configuration file to be loaded to the container
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(classPathXml);
      
              // 3. Get all bean objects in the container
              //Gets the bean name of all bean objects
              String[] beanNames = context.getBeanDefinitionNames();
              //Printout bean object
              for (String beanName : beanNames){
                  Dog dog = context.getBean(beanName,Dog.class);
                  System.out.println(String.format("bean name:%s,bean Object name value:%s,bean Object age value:%d",beanName,dog.getName(),dog.getAge()));
              }
      
          }
      }
      
    • Operation results

      bean name:dog1,bean Object name value:Xiaobai,bean Object age value:1
      bean name:dog2,bean Object name value:chinese rhubarb,bean Object age value:2
      

2. Creating bean objects using static factory methods

  • Explanation:

    • Create a static factory, provide some static methods internally to generate the required bean objects, and hand over the objects created by these static methods to the spring container for use
  • Basic format:

    <bean id="bean name" class="Static factory full classpath" factory-method="Method name of static factory">
        <constructor-arg index="0" value="bean Value of" ref="Referenced bean name" />
        <constructor-arg index="1" value="bean Value of" ref="Referenced bean name" />
        ....
    </bean>
    
    • Factory method: its value is the method name of the called bean object. This method is used to return the required bean object. The method must be static
  • case

    • The entity class is Dog class

    • Static factory

      package com.spring.study;
      
      public class DogStaticFactory {
      
          /**
           * Creating a Dog object with a static parameterless method
           * @return
           */
          public static Dog buildOne(){
              System.out.println("==============Static no parameters buildOne Method called==============");
      
              return new Dog();
          }
      
          /**
           * Creating a Dog object with a static parameterized method
           * @param name
           * @param age
           * @return
           */
          public static Dog buildTwo(String name, int age){
              System.out.println("==============Static parametric buildTwo Method called==============");
      
              return new Dog(name, age);
          }
      }
      
    • configuration file

      <?xml version="1.0" encoding="UTF-8"?>
      <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 http://www.springframework.org/schema/beans/spring-beans.xsd">
          <!--    Created by factory calling static parameterless methods bean object-->
          <bean id="dog1" class="com.spring.study.DogStaticFactory" factory-method="buildOne"/>
      
          <!--    Create by calling static parametric methods through the factory bean object-->
          <bean id="dog2" class="com.spring.study.DogStaticFactory" factory-method="buildTwo">
              <constructor-arg index="0" value="Er Gouzi"/>
              <constructor-arg index="1" value="3"/>
          </bean>
      </beans>
      
    • Test class

      package com.spring.test;
      
      import com.spring.study.Dog;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestStaticFactory {
          public static void main(String[] args) {
              // 1. Define bean configuration file location
              String classPathXml = "classpath:dogStaticFactory.xml";
      
              // 2. Create a ClassPathXmlApplicationContext container and specify the bean configuration file to be loaded to the container
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(classPathXml);
      
              // 3. Get all bean objects in the container
              //Gets the bean name of all bean objects
              String[] beanNames = context.getBeanDefinitionNames();
              //Printout bean object
              for (String beanName : beanNames){
                  Dog dog = context.getBean(beanName,Dog.class);
                  System.out.println(String.format("bean name:%s,bean Object name value:%s,bean Object age value:%d",beanName,dog.getName(),dog.getAge()));
              }
          }
      }
      
    • Operation results

      ==============Static no parameters buildOne Method called==============
      ==============Static parametric buildTwo Method called==============
      bean name:dog1,bean Object name value:Xiaobai,bean Object age value:1
      bean name:dog2,bean Object name value:Er Gouzi,bean Object age value:3
      

3. Create a bean object using the instance factory method

  • Explanation:

    • Make the Spring container call the instance methods of some instantiated bean objects to generate the required bean objects
  • Basic format:

    <bean id="bean name" factory-bean="Of the instance object to call bean name" factory-method="To call bean Object's instance method name">
        <constructor-arg index="0" value="bean Value of" ref="Referenced bean name" />
        <constructor-arg index="1" value="bean Value of" ref="Referenced bean name" />
        ....
    </bean>
    
    • Factory bean: its value is the bean name of the bean object to be called
    • Factory method: its value is the method name of the called bean object, which is used to return the required bean object
    • Flow: the container finds a bean object through the value of factory-bean, then determines a method to call the bean object according to the value of factory-method, and finally calls the method to return the bean object needed.
  • case

    • The entity class is Dog class

    • Instance factory class

      package com.spring.study;
      
      public class DogInstanceFactory {
      
          /**
           * Create a bean object by calling the parameterless constructor method
           * @return
           */
          public Dog buildOne(){
              System.out.println("==============buildOne Method called==============");
      
              return new Dog();
          }
      
          /**
           * Create a bean object by calling a parameterized constructor
           * @param name
           * @param age
           * @return
           */
          public Dog buildTwo(String name, int age){
              System.out.println("==============buildTwo Method called==============");
      
              return new Dog(name, age);
          }
      }
      
    • configuration file

      <?xml version="1.0" encoding="UTF-8"?>
      <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 http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--    Define a factory instance-->
          <bean id="dogIntanceFactory" class="com.spring.study.DogInstanceFactory"/>
      
          <!--    Created by calling the parameterless constructor method through the factory bean object-->
          <bean id="dog1" factory-bean="dogIntanceFactory" factory-method="buildOne"/>
      
          <!--    Created by calling a parameterized constructor through a factory bean object-->
          <bean id="dog2" factory-bean="dogIntanceFactory" factory-method="buildTwo">
              <constructor-arg index="0" value="godson "/>
              <constructor-arg index="1" value="4"/>
          </bean>
      </beans>
      
    • Test class

      package com.spring.test;
      
      import com.spring.study.Dog;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestInstanceFactory {
          public static void main(String[] args) {
              // 1. Define bean configuration file location
              String classPathXml = "classpath:dogInstanceFactory.xml";
      
              // 2. Create a ClassPathXmlApplicationContext container and specify the bean configuration file to be loaded to the container
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(classPathXml);
      
              // 3. Get all bean objects in the container
              //Gets the bean name of all bean objects
              String[] beanNames = new String[]{"dog1","dog2"};
              //Printout bean object
              for (String beanName : beanNames){
                  Dog dog = context.getBean(beanName,Dog.class);
                  System.out.println(String.format("bean name:%s,bean Object name value:%s,bean Object age value:%d",beanName,dog.getName(),dog.getAge()));
              }
          }
      }
      
    • Operation results

      ==============buildOne Method called==============
      ==============buildTwo Method called==============
      bean name:dog1,bean Object name value:Xiaobai,bean Object age value:1
      bean name:dog2,bean Object name value:godson ,bean Object age value:4
      

4. Implement FactoryBean interface to create bean object

  • In general, the spring container instantiates a bean by specifying the implementation class using the class attribute of the bean element through the reflection mechanism. In some cases, the process of instantiating a bean is complex. If you follow the traditional method, you need to provide a lot of configuration information in the bean. The flexibility of configuration mode is limited. At this time, a simple scheme may be obtained by coding. Spring provides a factory class interface of org.springframework.bean.factory.FactoryBean for this purpose. Users can customize the logic of instantiating beans by implementing this interface.

  • Ending with a bean indicates that it is a bean. Different from ordinary beans: it is a bean that implements the FactoryBean interface. What is obtained from the BeanFactory according to the bean name of the bean object is actually the object returned by the getObject method of the FactoryBean, not the FactoryBean itself. If you want to obtain the FactoryBean object, please add an & symbol in front of the bean name of the bean object. Take Dog class as an ex amp le,

    Dog dog = new ClassPathXmlApplicationContext("classpath:dogFactoryBean.xml).getBean("&dog2"))
    
  • FactoryBean interface source code

    package org.springframework.beans.factory;
    
    import org.springframework.lang.Nullable;
    
    public interface FactoryBean<T> {
        String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
        
    	/**
         * Returns the created object
         */
        @Nullable
        T getObject() throws Exception;
    	
        /**
         * Returns the type of object to be created
         */
        @Nullable
        Class<?> getObjectType();
    	
        /**
        * bean Is the object a singleton
        **/
        default boolean isSingleton() {
            return true;
        }
    }
    
    • getObject method, the developer implements the creation method of the bean object and returns the bean object to the Spring container
    • getObjectType method, the developer specifies the type of bean to be created
    • The isSingleton method indicates whether the object created through this interface is a singleton. If false is returned, the getObject method will be called to generate a new bean object every time the object is obtained from the container. The default is a singleton object.
  • Basic format:

    <bean id="bean name" class="FactoryBean Interface implementation class" />
    
    • The format is the same as bean element
  • case

    • Entity class is Dog class

    • FactoryBean interface implementation class

      package com.spring.study;
      
      import org.springframework.beans.factory.FactoryBean;
      
      public class DogFactoryBean implements FactoryBean<Dog> {
      
          /**
           * Set whether it is a singleton object
           */
          private boolean singleton;
      
          public boolean getSingleton() {
              return singleton;
          }
      
          public void setSingleton(boolean singleton) {
              this.singleton = singleton;
          }
      
          /**
           * Return the created object -- the bean object created by calling the parameterless constructor method
           * @return
           * @throws Exception
           */
          @Override
          public Dog getObject() throws Exception {
              if (this.singleton){
                  System.out.println("=========The singleton object is about to be printed=========");
              }else{
                  System.out.println("=========Non singleton objects are about to be printed=========");
              }
      
              return new Dog();
          }
      
          /**
           * Returns the type of object to be created
           * @return
           */
          @Override
          public Class<?> getObjectType() {
              return Dog.class;
          }
      
          /**
           * Set whether the bean object is a singleton
           * @return
           */
          @Override
          public boolean isSingleton() {
              return this.singleton;
          }
      
          public DogFactoryBean(boolean singleton) {
              this.singleton = singleton;
          }
      
          public DogFactoryBean() {
              
          }
      }
      
      • The private property singleton is Boolean and the default value is false, so the bean object returned by the getObject method of this implementation class is a non singleton object by default
    • configuration file

      <?xml version="1.0" encoding="UTF-8"?>
      <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 http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--    definition DogFactoryBean Object to get Dog Object is a non singleton object-->
          <bean id="dog1" class="com.spring.study.DogFactoryBean"/>
      
          <!--    definition DogFactoryBean Object to get Dog Object is a singleton object-->
          <bean id="dog2" class="com.spring.study.DogFactoryBean">
              <constructor-arg index="0" value="true"/>
          </bean>
      
      </beans>
      
    • Test class

      package com.spring.test;
      
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestFactoryBean {
          public static void main(String[] args) {
              // 1. Define bean configuration file location
              String classPathXml = "classpath:dogFactoryBean.xml";
      
              // 2. Create a ClassPathXmlApplicationContext container and specify the bean configuration file to be loaded to the container
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(classPathXml);
      
              // 3. Gets the bean names of all bean objects in the container
              String[] beanNames = context.getBeanDefinitionNames();
      
              // 4. Print out the memory address of the bean object to determine whether the obtained bean object is the same object in singleton mode
              for (String beanName : beanNames){
                  for (int i = 0; i < 2; i++){
                      System.out.println(String.format("bean name:%s,bean Object memory address:%s",beanName,context.getBean(beanName)));
                  }
              }
              System.out.println("FactoryBean Implementation class object:" + context.getBean("&dog2"));
          }
      }
      
    • Operation results

      =========Non singleton objects are about to be printed=========
      bean name:dog1,bean Object memory address:com.spring.study.Dog@cd2dae5
      =========Non singleton objects are about to be printed=========
      bean name:dog1,bean Object memory address:com.spring.study.Dog@3a883ce7
      =========The singleton object is about to be printed=========
      bean name:dog2,bean Object memory address:com.spring.study.Dog@4973813a
      bean name:dog2,bean Object memory address:com.spring.study.Dog@4973813a
      FactoryBean Implementation class object:com.spring.study.DogFactoryBean@6321e813
      
      • From the memory address printed by the running result, if it is in singleton mode, each time a bean object is created, the getObject method is called only once from beginning to end, and the same bean object is used; If it is in non singleton mode, each time you create a bean object, you need to call the getObject method and create a new bean object

    reference resources: Java charging Society,Beet Bobo

Posted by VinnyWolf on Mon, 06 Dec 2021 22:12:24 -0800