Full code address for this article: https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/factorybean
FactoryBean and BeanFactory have long been plagued by developers because of their similarity in naming.
BeanFactory, the well-known Spring core interface, provides the most basic functionality of the IoC container.But explaining a FactoryBean sentence may not be clear.We'll step through the following examples to illustrate what FactoryBean is and what capabilities it provides.
/** * cloth * Contains color attributes * Created by OKevin On 2019/9/3 **/ public class Cloth { private Red red; //Omit setter/getter method }
When I first initialize a Cloth object, I want the Red object to be assigned a value, so I'll new a Red object in Cloth's construction method.
public Cloth() { red = new Red(); }
But as the business grows, I want Cloth's color property to be Blue Blue, so I'll modify the code to abstract the Red and Blue classes into a Color interface, and the Cloth code will be refactored:
/** * cloth * Contains color attributes * Created by OKevin On 2019/9/3 **/ public class Cloth { private Color color; public Cloth() { color = new Blue(); } //Omit setter/getter method }
As the business goes further, the color attributes in the Cloth class will be assigned Red based on certain conditions, and we'll continue refactoring the code:
/** * cloth * Contains color attributes * Created by OKevin On 2019/9/3 **/ public class Cloth { private Color color; public Cloth() { if (condition()) { color = new Blue(); } else { color = new Red(); } } //Omit setter/getter method }
This code does work, but if new conditions continue to be added to the business, then we will change the construction method of the Cloth class. We think the Cloth method is a core business object and should not be modified frequently, and it is too redundant to create the Color object in the construction method.The principle of single responsibility is not met, so we created the Color object using the factory method pattern.
Static Factory Method
Again, we refactored the Cloth class as follows (to make the sample code more concise, the following example creates only Red objects):
/** * cloth * Contains color attributes * Created by OKevin On 2019/9/3 **/ public class Cloth { private Color color; public Cloth() { color = StaticColorFactory.newInstance(); } //Omit setter/getter method }
/** * Static Factory Method * Created by OKevin On 2019/9/3 **/ public class StaticColorFactory { public static Color getInstance() { return new Red(); } }
What if we want to create a specific object instance in the Spring container using the static factory method?
As you know, to put an object instance under the management of the Spring container, we usually configure it with the following XML:
<bean id="cloth" class="com.coderbuff.bean.Cloth"> <property name="color" ref="red"/> </bean> <bean id="red" class="com.coderbuff.bean.Red" />
However, at this point, Red object instances are not managed by Spring containers, but are created by static factory methods, and we should talk about modifying the XML configuration to the following:
<bean id="cloth" class="com.coderbuff.bean.Cloth"> <property name="color" ref="red"/> </bean> <bean id="red" class="com.coderbuff.factory.StaticColorFactory" factory-method="getInstance" />
This is a specific way Spring supports static factory methods for creating object instances.This allows us to create object instances in Spring using the static factory method.
Instance Factory Method
There is a static factory method, there is a non-static factory method, the difference is that the method is not static.
/** * Instance Factory Method * Created by OKevin On 2019/9/3 **/ public class ColorFactory { public Color getInstance() { return new Red(); } }
Instance factory methods have slightly different XML configurations in Spring:
<bean id="cloth" class="com.coderbuff.bean.Cloth"> <property name="color" ref="red"/> </bean> <bean id="colorFactory" class="com.coderbuff.factory.ColorFactory"/> <bean id="red" factory-bean="colorFactory" factory-method="getInstance"/>
As you can see from the configuration, we need to instantiate the factory in Spring first, then the Red object through the factory object.
With an understanding of factory methods for creating object instances in Spring, FactoryBean is actually meant to simplify this for us.Below we will create a Red object using FactoryBean.
FactoryBean
/** * Created by OKevin On 2019/9/3 **/ public class ColorFactoryBean implements FactoryBean<Color> { public Color getObject() throws Exception { return new Red(); } public Class<?> getObjectType() { return Red.class; } public boolean isSingleton() { return false; } }
By implementing FactoryBean, the XML configuration is as follows:
<bean id="cloth" class="com.coderbuff.bean.Cloth"> <property name="color" ref="red"/> </bean> <bean id="red" class="com.coderbuff.factory.ColorFactoryBean"/>
Instead of configuring the properties like the factory method, simply follow the normal Bean injection. Because of special processing inside Spring, a Bean named "red" is not a ColorFactoryBean, but an object returned from the getObject in its method.If you really want to get an object instance of a ColorFactoryBean, add'&'before the name of the Bean ('&red').
Seeing this, do you have a little understanding of FactoryBean?One of the most typical applications of FactoryBean in Spring is the proxy object used to create AOP.
We know that AOP actually creates a proxy object at runtime by Spring, that is, this object was created at runtime, not defined at the beginning, which fits well with the factory method pattern.More specifically, AOP proxy objects create a proxy object at runtime through Java's reflection mechanism, which weaves methods into the target method of the proxy object according to business requirements.This object is called ProxyFactoryBean in Spring.
ProxyFactoryBean
We'll create a face of a Red object by comparing "Old" and execute a statement before and after its print method executes.It's so old because we tend to annotate rather than torment ourselves to write a face-to-face object.
/** * Around Advice * Created by OKevin On 2019/9/4 **/ public class LogAround implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("Invoke target method to print log"); Object result = invocation.proceed(); System.out.println("Print the log after calling the target method"); return result; } }
At this point we need ProxyFactoryBean's involvement to create a proxy object for us and managed by the Spring container. Based on the experience of ColorFactoryBean above, ProxyFacoryBean should also be configured as follows:
<bean id="xxx" class="org.springframework.aop.framework.ProxyFactoryBean" />
The answer is yes, but ProxyFactoryBean has several more parameters. Since it is a proxy object, the target object and target method are essential. The actual XLM configuration is as follows:
<bean id="logAround" class="com.coderbuff.aop.LogAround"/> <bean id="red" class="com.coderbuff.bean.Red"/> <bean id="proxyRed" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.coderbuff.bean.Color"/> <property name="interceptorNames" value="logAround"/> <property name="target" ref="red"/> <property name="proxyTargetClass" value="true"/> </bean>
Through the test program, ProxyFactoryBean did generate a proxy object.
public class ProxyFactoryBeanTest { private ClassPathXmlApplicationContext ctx; @Before public void init() { ctx = new ClassPathXmlApplicationContext("spring-proxyfactorybean.xml"); } @Test public void testProxyFactory() { Red proxyRed = (Red) ctx.getBean("proxyRed"); proxyRed.print(); } }
Therefore, Factory Bean provides a more flexible way for us to instantiate beans, allowing us to create more complex instances of beans.
Full code address for this article: https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/factorybean