Definite goal
Let me briefly describe the problem that this article wants to solve: how to no longer use Spring to create bean instances in Spring, but transfer the bean creation process to the developers.
Clear thinking
How to create a Bean instance:
1) Through the constructor (with or without parameters)
Method: <bean id=""/>
2) Through the static factory method
Method: <bean id="" factory-method="静态工厂方法"/>
Note: The factory class instance is not created
3) Through the instance factory method (non-static method)
Way:
<bean id="factory"/>
<bean id="" factory-bean="factory" factory-method="实例工厂方法"/>
Note: The factory class instance is created
Practical method
Example 1 :
need:
1 I don’t want to instantiate the bean when bean.xml is loaded, but I want to separate the loaded bean.xml from the instantiated object.
2 Implement singleton bean
In the above situations, beans can be created through factory-method.
In this way, when bean.xml is loaded, the bean will not be instantiated directly, but will only start to be truly instantiated when the method referred to by factory-method is called.
Implementation: Create a singleton bean through spring factory-method
First create a singleton object through a static inner class
package com.spring.test.factorymethod;public class Stage { public void perform(){ System.out.println("Show start..."); } private Stage(){ } private static class StageSingletonHolder{ static Stage instance = new Stage(); } public static Stage getInstance(){ return StageSingletonHolder.instance; }}Specify loading method in spring configuration file getInstance
<?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" factory-method="getInstance"></bean></beans>
Get instance by calling beans in 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(); }}Execution results
January 24, 2015 6:38:18 pm 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 hierarchyJan 24, 2015 6:38:19 pm org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions information: Loading XML bean definitions from class path resource [bean.xml] January 24, 2015 6:38:19 pm 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 The hierarchy performance begins...
Introduction to factory method creation bean
1. Create a Bean using a static factory method
When creating a bean instance using the static factory method, the class attribute must also be specified, but at this time the class attribute is not the implementation class that specifies the bean instance, but the static factory class. Because Spring needs to know which factory to use to create the Bean instance. In addition, you need to use factory-method to specify the static factory method name. Spring will call the static factory method (may contain a set of parameters) to return a bean instance. Once the specified bean instance is obtained, the processing steps after Spring are exactly the same as creating the bean instance using ordinary methods. It should be noted that when using static factory methods to create beans, this factory-method must be static. This passage sounds a little dizzy, without saying much, please add the code:
First define an interface, and the static method will produce an instance of the interface:
public interface Animal { public void saysHello();}Here are two implementation classes of the interface:
public class Cat implements Animal { private String msg; //The setter method required during dependency injection public void setMsg(String msg){ this.msg = msg; } @Override public void saysHello(){ System.out.println(msg + ", meow~meow~"); }} public class Dog implements Animal { private String msg; //The setter method required during dependency injection public void setMsg(String msg){ this.msg = msg; } @Override public void saysHello(){ System.out.println(msg + ", strong~ strong~"); }}The AnimalFactory factory below contains a static method of getAnimal, which will determine which object to create based on the passed parameters. 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 need to specify that Spring uses AnimalFactory to generate Animal objects, you can configure the following in the Spring configuration file:
<!-- Configure the getAnimalFactory's getAnimal method to generate Cat --><bean id="cat" factory-method="getAnimal"> <!-- Configure the parameters of the static factory method, the getAnimal method will generate Cat-type objects --> <constructor-arg value="cat" /> <!-- Normal properties injected through setter--> <property name="msg" value="cat" /></bean><!-- Configure the getAnimalFactory's getAnimal method to generate Dog --><bean id="dog" factory-method="getAnimal"> <!-- Configure the parameters of the static factory method, the getAnimal method will generate Dog-type objects --> <constructor-arg value="dog" /> <!-- Normal properties injected through setter--> <property name="msg" value="dog" /></bean>
From the above configuration, we can see that the class and factory-method of the two beans configurations of cat and dog are exactly the same, 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 this static factory method are different, use the <constructor-arg /> element to specify parameters for the static factory method.
The method of the main program to obtain two bean instances cat and dog remains unchanged. You only need 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 result:
<code>Cat, meow~meow~dog, strong~strong~</code>
When creating an instance using a static factory method, you must provide the factory class and the static factory method that generates the instance. When creating an instance through a static factory method, you need to make the following changes to the Spring configuration file;
The class attribute is not the implementation class of the Bean instance, but the static factory class that generates the Bean instance
Use factory-method to specify a static factory method for producing a Bean instance
If the static factory method requires parameters, use the <constructor-arg /> element to configure it
When we specify that Spring uses a static factory method to create a bean instance, Spring will first parse the configuration file, and call the static factory method of the static factory class through reflection based on the information specified by the configuration file, and use the return value of the static factory method as the bean instance. In this process, Spring is no longer responsible for creating a bean instance, and the bean instance is provided by the static factory method provided by the user.
2. Create a Bean using the instance factory method
The instance factory method is only a little different from the static factory method: calling the static factory method only requires using the factory class, and calling the instance factory method must use the factory instance. Therefore, there is only one difference in Spring configuration: configure the static factory method to specify the static factory class, and configure the instance factory method to specify the factory instance. The same example above changes AnimalFactory to:
public clas AnimalFactory { public Animal getAnimal(String type){ //Here, the static keyword is only removed if ("cat".equalsIgnoreCase(type)){ return new Cat(); } else { return new Dog(); } }}The Spring file is modified to:
<!-- Configure the factory class first --><bean id="animalFactory" /><!-- Here we use factory-bean to specify the instance factory class object --><bean id="cat" factory-bean="animalFactory" factory-method="getAnimal"> <!-- Also specify the parameters of factory-method--> <constructor-arg value="cat" /> <property name="msg" value="cat" /></bean><bean id="dog" factory-bean="animalFactory" factory-method="getAnimal"> <constructor-arg value="dog" /> <property name="msg" value="Dog" /></bean>
The test class does not need to be modified, the output results are the same as above.
In many cases, <bean id="bean1" class="..." /> is used to define a bean. This way Spring will call the default parameterless constructor to create a bean instance. In addition, you can also use factory to create bean instances to separate bean creation and use, and hand over the bean creation work to the factory to complete.
There are three ways to configure factory beans.
Abstract interface:
public interface IMusicBox { public void play(); } 1. Obtain Bean examples for static factory method
Factory category:
public class MusicBoxFactory { public static IMusicBox createMusicBox(){ return new IMusicBox(){ public void play(){ System.out.println("Play piano..."); } }; } }Configuration file:
<bean id="musicBox" factory-method="createMusicBox" />
Test class:
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-config.xml"); IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox"); musicbox.play(); }2. The method of factory instance obtains bean instance
Factory category:
public class MusicBoxFactory { public IMusicBox createMusicBox(){//No static modification return new IMusicBox(){ public void play(){ System.out.println("Play piano..."); } }; } }Configuration file:
<bean id="factoryBean" /> <bean id="musicBox" factory-bean="factoryBean" factory-method="createMusicBox" />
The "factory-bean" attribute specifies the factory bean, and the "factory-method" attribute specifies the factory method to obtain the bean instance.
Test class:
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-config.xml"); IMusicBox musicbox = (IMusicBox)ctx.getBean("musicBox"); musicbox.play(); } 3. Factory class implements org.springframework.beans.factory.FacotryBean interface
Factory category:
import org.springframework.beans.factory.FactoryBean; public class MusicBoxFactory2 implements FactoryBean { public Object getObject() throws Exception { return new IMusicBox(){ public void play(){ System.out.println("Play piano..."); } }; } public Class getObjectType() { return IMusicBox.class; } public boolean isSingleton() { return false; } }Configuration file:
<bean id="musicBox"/>
Test class:
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-config.xml"); //Not added& Returns the "product" of 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()); }Classes that implement FactoryBean interface will not be regarded as ordinary beans, Spring will automatically detect them, and call the getObject method to get the bean instance.
Summarize
This is the end of the introduction to instantiating bean instances in Spring factory methods. If you have any shortcomings, you can leave a message to point out. Thank you friends for your support for this site!