Spring factory method and FactoryBean (instantiated Bean)

In this blog, about factory methods and FactoryBean, in fact, Spring no longer uses Spring to create Bean instances, but uses factory methods and FactoryBean to transfer the Bean creation process to developers.

This blog directory

1. Understand what factory methods and FactoryBeans do
2. The static factory method instantiates the bean
3. Factory method instantiate Bean
4, FactoryBean instantiate Bean (factory Bean)

1. Understand what factory methods and FactoryBeans do

The author thinks this is the most important part in this blog. You have to understand what the factory method and FactoryBean do, and which ones are similar.

First of all, usually in Spring, we will use XML or annotation to configure beans. And in XML way there are three ways to instantiate beans
  • reflection mode
  • Factory Method Pattern
  • FactoryBean pattern

The reflection mode is often used, that is, in the bean configuration, the full class name of the bean is declared. In this blog, the author will introduce the factory mode and the instantiation of the bean in the FactoryBean mode, and have a deep understanding of the two modes.


Second, the static factory method instantiate Bean (Static Factory Method)

Consider a scenario where a singleton class is configured with beans in Spring. Generally speaking, an instance of a singleton class can only be created through a static factory method (the author is here to extend the example of "Spring IN ACTION"): The following example is a stage class, and there is only one stage, that is, a static factory method is used.


Stage.java

package com.linjie.staticfactory;

/**
 * @author LinJie
 * @Description:这是一个舞台单例类(所以需要静态工厂方法)
 * 每个参赛者用同一个舞台
 */
public class Stage {
    private static Stage instance;
    public static Stage getInstance() {
        if(instance == null){
            instance = new Stage();
        }
        return instance;
    }

    //搭建舞台完成
    public void CreateStageSuccess() {
        System.out.println("舞台搭建完成,舞者可以上台了");
    }
}

Dancer.java (dancer class)

package com.linjie.staticfactory;
/**
 * @author LinJie
 * @Description:这是每个舞者的类,但他们使用同一个舞台
 */
public class Dancer {
    private Stage stage;

    /**
     * @param stage the stage to set
     */
    public void setStage(Stage stage) {
        this.stage = stage;
    }

    //LinJie dancer上台
    public void Show() {
        stage.CreateStageSuccess();
        System.out.println("LinJie dancer上台");
    }
}

test class

package com.linjie.staticfactory;
/**
 * @author LinJie
 * @Description:这是每个舞者的类,但他们使用同一个舞台
 */
public class Dancer {
    private Stage stage;

    /**
     * @param stage the stage to set
     */
    public void setStage(Stage stage) {
        this.stage = stage;
    }

    //LinJie dancer上台
    public void Show() {
        stage.CreateStageSuccess();
        System.out.println("LinJie dancer上台");
    }
}

applicationContext.xml

<?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">

    <!-- 静态工厂实例化Bean -->
    <bean id="stage" class="com.linjie.staticfactory.Stage" factory-method="getInstance"></bean>

    <bean id="dancer" class="com.linjie.staticfactory.Dancer">
        <property name="stage" ref="stage"></property>
    </bean> 

</beans>

result

舞台搭建完成,舞者可以上台了
LinJie dancer上台

Note: Stage does not have a public constructor. Instead, the static method getInstance() returns the same instance every time it is called (because there is only one stage), so how to configure a Stage without a public constructor as a bean in Spring? ?

You can see that in applicationContext.xml

  • factory-method: allows us to call a specified static factory method, thereby creating an instance of a class instead of a constructor (that is, specifying the static factory method name)
  • class: It is no longer the implementation class of the Bean instance, but the static factory class of the Bean instance (the above example does not reflect this, the following example is implemented based on this)
  • If the static factory method requires a parameter, use the config for it

Stage.java (a stage class, name can be passed)

package com.linjie.staticfactory;
/**
 * @author LinJie
 * @Description:一个舞台类,可以给舞台赋值(其实这里我只想演示传参)
 */
public class Stage {
    private String name;

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    //搭建舞台
    public void Show() {
        System.out.println(name+"舞台搭建完成");
    }
}

staticfactory.java (static factory method implementation class)

package com.linjie.staticfactory;

/**
 * @author LinJie
 * @Description:这是一个静态工厂方法的类,用于创建单例舞台
 */
public class staticfactory {
    private static Stage instance;
    public static Stage getInstance() {
        if(instance == null){
            instance = new Stage();
        }
        return instance;
    }
}

test class

package com.linjie.staticfactory;

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

public class staticFactoryBean {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Stage stage = (Stage) context.getBean("stage");
        stage.Show();
    }
}

applicationContext.xml

<?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">

    <!-- 静态工厂实例化Bean -->
    <!-- class:这里不再是Bean实例的实现类,而是生成Bean实例的静态工厂类 -->
    <bean id="stage" class="com.linjie.staticfactory.staticfactory" factory-method="getInstance">
        <property name="name" value="haha"></property>
    </bean> 
</beans>

result

write picture description here

Note: The value of the class attribute here is not the implementation class of the Bean instance, but the static factory class that generates the Bean instance


Third, the factory method instantiate Bean (Instance Factory Method)

ABean.java (the implementation class of a Bean instance)

package com.linjie.factory;

/**
 * @author LinJie
 * @Description
 */
public class ABean {
    //利用工厂方法实例化Bean成功显示
    public void show() {
        System.out.println("工厂方法实例化Bean成功");
    }
}

FactoryBean.java (factory method)

package com.linjie.factory;

/**
 * @author LinJie
 * @Description:工厂方法实例化Bean
 */
public class FactoryBean {
    public ABean getABean() {
        return new ABean();
    }
}

test class

package com.linjie.factory;

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

public class FactoryTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        ABean abean = (ABean) context.getBean("abean");
        abean.show();
    }
}

applicationContext.xml

<?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">

    <!-- 工厂实例化Bean -->
    <bean id="factorybean" class="com.linjie.factory.FactoryBean"></bean>

    <bean id="abean" factory-bean="factorybean" factory-method="getABean"></bean> 

</beans>

result

write picture description here

in the properties of applicationContext

  • factory-bean: Specify the factory class instance where the factory method is located (that is, the id of the factory method bean, similar to ref)
  • factory-method: or specify the factory method name
  • You can also specify method call parameters by

Fourth, FactoryBean instantiate Bean

FactoryBean is an interface provided by the Spring container to extend the instantiation logic of container objects. Please do not confuse it with the container name BeanFactory. FactoryBean, its subject is Bean, and its attribute is Factory, that is to say, it is just a Bean like other objects registered in the container, but the type of Bean itself is the factory that produces objects

Application scenarios

When the instance process of some objects is too cumbersome, the configuration through XML is too complicated, so that we would rather use Java code to complete the instantiation process, or when some third-party libraries cannot be directly registered in the Spring container, then You can implement the org.spring-framework.beans.factory.FactoryBean interface and give your own object instantiation code. Of course, it is also possible to implement a custom factory. But FactoryBean is standard in Spring

Instructions

1. Create the implementation class of FactoryBean

2. Implement the following three methods

- public String getObject() throws Exception:该方法返回该FactoryBean“生产”的对象。我们需要实现该方法以给出自己对象实例化逻辑 
- public Class<?> getObjectType():该方法仅返回getObject()方法所返回的对象的类型。如果预先无法确定,则返回null
- public boolean isSingleton() :该方法返回结果用于表明,getObject()“生产”的对象是否要以singleton(单例)形式存于容器中。如果以singleton形式存在,则返回true,否则返回false

nameFactoryBean implementation class

package com.linjie.factorybean;

import org.springframework.beans.factory.FactoryBean;

public class nameFactoryBean<T> implements FactoryBean<String> {
    //该方法返回该FactoryBean“生产”的对象
    //我们需要实现该方法以给出自己对象实例化逻辑
    @Override
    public String getObject() throws Exception {
        return new String("linjie");
    }

    //该方法仅返回getObject()方法所返回的对象的类型
    //如果预先无法确定,则返回null
    @Override
    public Class<?> getObjectType() {
        return null;
    }

    //该方法返回结果用于表明,getObject()“生产”的对象是否要以singleton(单例)形式存于容器中
    //如果以singleton形式存在,则返回true,否则返回false
    @Override
    public boolean isSingleton() {
        return false;
    }

}

test class

package com.linjie.factorybean;

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

public class factorybeanTest {
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        String bean = (String) context.getBean("bean");
        System.out.println(bean);
    }
}

applicationContext.xml

<?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">  

     <!-- FactoryBean实例化Bean -->
     <bean id="bean" class="com.linjie.factorybean.nameFactoryBean"></bean> 

</beans>

result

write picture description here

Difference between FactoryBean and BeanFactory

  • FactoryBean: As the author explained above, it ends with Bean, indicating that it is a Bean. It is not a simple Bean, but a factory Bean that can produce objects or modify objects.
  • BeanFactory: It is a form of Spring IoC container, providing complete IoC service support. It can also be seen that the subject is Factory, which is a factory that manages beans. About BeanFactory, you can go to another blog of the author https://blog. csdn.net/w_linux/article/details/80025048

refer to

"Spring Revealed"

《Spring IN ACTION》

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324823649&siteId=291194637