Spring factory method creates (instantiates) bean instance code

  • 2020-12-19 20:59:21
  • OfStack

Specific goals

A brief description of the problem this article addresses is how to move the Bean creation process from Spring to Bean instances in Spring.

clear

How to create an Bean instance:

1) Through the constructor (with or without parameters)

Method: <bean id="" class=""/>

2) Through the static factory method

Method: <bean id="" class="工厂类" factory-method="静态工厂方法"/>

Note: The factory class instance was not created

3) Through the instance factory method (non-static method)

Method:

<bean id="factory" class="工厂类"/>

<bean id="" factory-bean="factory" factory-method="实例工厂方法"/>

Note: Instances of factory classes are created

Methods the practical

Example 1:

Requirements:

1 Instead of instantiating bean when bean.xml is loaded, you want to separate the loading of ES48en.xml from the instantiated object.

bean for singletons

In all of the above cases, bean can be created using the factory method ES55en-ES56en.

In this way, when bean.xml is reloaded, bean is not instantiated directly, but the actual instantiation begins when the method referred to by factory-ES64en is called.

Implementation: bean singleton is created using ES68en-ES69en of spring
First, create a singleton object with a static inner class


package com.spring.test.factorymethod;

public class Stage {
  public void perform(){
    System.out.println(" Show began ...");
  }
  private Stage(){
    
  }
  private static class StageSingletonHolder{
    static Stage instance = new Stage();
  }
  public static Stage getInstance(){
    return StageSingletonHolder.instance;
  }
}

Specify the method getInstance to load in the spring configuration file


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>

Call bean to get the instance from the application context


package com.spring.test.factorymethod;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {
  public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
    Stage stage = ((Stage)ctx.getBean("theStage"));//.getInstance();
    stage.perform();
  }
}

The execution result


1 month  24, 2015 6:38:18  In the afternoon  org.springframework.context.support.AbstractApplicationContext prepareRefresh
 information : Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@512dbd1a: startup date [Sat Jan 24 18:38:18 CST 2015]; root of context hierarchy
1 month  24, 2015 6:38:19  In the afternoon  org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
 information : Loading XML bean definitions from class path resource [bean.xml]
1 month  24, 2015 6:38:19  In the afternoon  org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
 information : Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2d1879ea: defining beans [duke,sonnet29,poeticDuke,theStage]; root of factory hierarchy
 Show began ...

The factory method to create bean is described

1. Create Bean using the static factory method

When you create an instance of Bean using a static factory method, the class attribute must also be specified, but in this case the class attribute does not specify an implementation class for an instance of Bean, but a static factory class. Because Spring needs to know which factory is used to create the Bean instance. In addition, factory-method will be used to specify the static factory method name. Spring will call the static factory method (which may contain a set of parameters) to return 1 instance of Bean. Once the specified Bean instance is obtained, the processing steps following Spring are exactly the same as creating an Bean instance using the normal method. It is important to note that when using static factory methods to create Bean, the ES108en-ES109en must be static. This explanation sounds a little confusing, without further ado, code:

Define an interface, and the static method will produce an instance of the interface:


public interface Animal {
  public void sayHello();
}

Here are the two implementation classes for the interface:


public class Cat implements Animal {
  private String msg;
  // Dependency injection is required setter methods 
  public void setMsg(String msg){
    this.msg = msg;
  }
  @Override
  public void sayHello(){
    System.out.println(msg + " Meow, ~ meow ~");
  }
}
 

public class Dog implements Animal {
  private String msg;
  // Dependency injection is required setter methods 
  public void setMsg(String msg){
    this.msg = msg;
  }
  @Override
  public void sayHello(){
    System.out.println(msg + " , ~ swan ~");
  }
}

The AnimalFactory factory below contains a static method of getAnimal that will determine which object to create based on the parameters passed in. This is a typical static factory design pattern.


public clas AnimalFactory {
  public static Animal getAnimal(String type){
    if ("cat".equalsIgnoreCase(type)){
      return new Cat();
    } else {
      return new Dog();
    }
  }
}

If you want to specify Spring to use AnimalFactory to generate Animal objects, you can do the following in the Spring configuration file:


<!--  configuration AnimalFactory the getAnimal Method to make it come into being Cat -->
<bean id="cat" class="com.abc.AnimalFactory" factory-method="getAnimal">
  <!--  Configure the parameters of the static factory method, getAnimal Method will produce Cat Object of type  -->
  <constructor-arg value="cat" />
  <!--  through setter Injected common properties  -->
  <property name="msg" value=" The cat cat " />
</bean>
<!--  configuration AnimalFactory the getAnimal Method to make it come into being Dog -->
<bean id="dog" class="com.abc.AnimalFactory" factory-method="getAnimal">
  <!--  Configure the parameters of the static factory method, getAnimal Method will produce Dog Object of type  -->
  <constructor-arg value="dog" />
  <!--  through setter Injected common properties  -->
  <property name="msg" value=" dog " />
</bean>

As you can see from the above configuration: cat and dog are identical to class and ES134en-ES135en for both Bean configurations, because both instances are generated using the same static factory class and the same static factory method. It is just that the parameters specified for the static factory method are different < constructor-arg / > Element to specify parameters for static factory methods.

The main program gets cat and dog instances without changing the method. Again, it only needs to call getBean() of the Spring container:


public class Test {
  public static void main(String args[]){
    ApplicationContext context = 
        new ClassPathXmlApplicationContext("applicationContext.xml");
    Animal a1 = context.getBean("cat", Animal.class);
    a1.sayHello();
    Animal a2 = context.getBean("dog", Animal.class);
    a2.sayHello();
  }
}

Output results:


<code class="hljs"> The cat cat, meow ~ meow ~
 Dogs, flourishing ~ swan ~</code>

When you create an instance using a static factory method, you must provide the factory class and the static factory method that generated the instance. You need to make the following changes to the Spring configuration file when you create an instance using the static factory method;

The class attribute is no longer an implementation class for an Bean instance, but a static factory class that generates an Bean instance

Use ES160en-method to specify a static factory method for producing Bean instances

If static factory methods require parameters, use < constructor-arg / > Element for which it is configured

When we specify Spring use the static factory methods to create Bean instance, Spring will parse configuration files, and according to the configuration file specified information, through reflection to invoke static factory class static factory methods, and the static factory methods return values as Bean instance, in the process, Spring no longer responsible for creating Bean instance, Bean instance is provided by the user provides static factory methods.

2. Create Bean using the instance factory method

Instance factory methods differ from static factory methods in only one respect: to invoke a static factory method, you only need to use the factory class; to invoke an instance factory method, you must use the factory instance. So there is only one difference in Spring configuration: the configuration static factory method specifies the static factory class, and the configuration instance factory method specifies the factory instance. In the same example above, AnimalFactory is modified to:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>
0

The Spring file is modified to:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>
1

The test class is not modified, and the output is the same as above.

It's used in many cases < bean id bean1 class = "="..." / > Define an bean, which will call the default no-argument constructor to create an instance of Bean. In addition, Bean instances can be created in factory mode to achieve the separation of Bean creation and use, leaving Bean creation to the factory.

Three ways to configure factory Bean.

Abstract interface:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>
2

1. Static factory method to obtain Bean instance

The factory class:


public class MusicBoxFactory { 
  public static IMusicBox createMusicBox(){ 
  return new IMusicBox(){ 
       public void play(){ 
    System.out.println("Play piano..."); 
     } 
  }; 
  } 
} 

Configuration file:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>
4

The test class:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>
5

2. Obtain the Bean instance by the method of the factory instance

The factory class:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>
6

Configuration file:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>
7

The "ES237en-ES238en" attribute specifies the factory Bean, and the "ES240en-ES241en" attribute specifies the factory method to obtain the Bean instance.

The test class:


public static void main(String[] args) { 
  ApplicationContext ctx =  
  new ClassPathXmlApplicationContext("bean-config.xml"); 
  IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox"); 
  musicbox.play(); 
} 

3, the factory class implements org. springframework. beans. factory. FacotryBean interface

The factory class:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/beans"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="theStage" class="com.spring.test.factorymethod.Stage"
     factory-method="getInstance"></bean>
</beans>
9

Configuration file:


<bean id="musicBox" class="test.spring.MusicBoxFactory2"/> 

The test class:


public static void main(String[] args) { 
  ApplicationContext ctx =  
  new ClassPathXmlApplicationContext("bean-config.xml"); 
  // Do not add  &  "Products" returned to the factory  
  IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox"); 
  musicbox.play(); 
  // add  &  Returns the factory class instance  
  Object obj = ctx.getBean("&musicBox");  
  System.out.println(obj.getClass().getName());  
 
} 

A class that implements the FactoryBean interface will not be treated as a normal Bean, and Spring will automatically detect and call the getObject method to get an instance of Bean

conclusion

Spring factory method instantiation bean instance introduction is here, any shortcomings, you can leave a comment. Thank you for your support!


Related articles: