Spring中老生常谈的FactoryBean
本文完整代码地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/factorybean
FactoryBean和BeanFactory由于在命名上极其相似,一直以来困扰了不少的开发者。
BeanFactory,耳熟能详的Spring核心接口,提供IoC容器的最基本功能。但要解释FactoryBean一句话可能就说不清楚了。我们将从下面的例子逐步说明,FactoryBean是什么,它提供了什么样的能力。
/**
* 布料
* 包含颜色属性
* Created by OKevin On 2019/9/3
**/
public class Cloth {
private Red red;
//省略setter/getter方法
}
当初始化一个Cloth对象时,我希望Red对象也被赋值,此时我将在Cloth的构造方法中new一个Red对象。
public Cloth() {
red = new Red();
}
但是随着业务的发展,我希望Cloth的颜色属性将是Blue蓝色,这时我将修改代码将Red和Blue类抽象出一个Color接口,Cloth代码将重构:
/**
* 布料
* 包含颜色属性
* Created by OKevin On 2019/9/3
**/
public class Cloth {
private Color color;
public Cloth() {
color = new Blue();
}
//省略setter/getter方法
}
业务又进一步发展,Cloth类中的颜色属性将会根据一定的条件赋值为Red红色,此时我们将代码继续重构:
/**
* 布料
* 包含颜色属性
* Created by OKevin On 2019/9/3
**/
public class Cloth {
private Color color;
public Cloth() {
if (condition()) {
color = new Blue();
} else {
color = new Red();
}
}
//省略setter/getter方法
}
这样的代码的确能运行,但如果有新的条件继续加入到业务中,此时我们又将改动Cloth类的构造方法,而我们认为Cloth方法是一个比较核心的业务对象,不应该经常对它进行修改,并且在构造方法中对于Color对象创建过于冗余,不符合单一职责的原则,所以我们将Color对象的创建过程通过工厂方法模式来完成。
静态工厂方法
我们再次将Cloth类进行如下重构(为了使示例代码更加简洁,下面的示例将只创建Red对象):
/**
* 布料
* 包含颜色属性
* Created by OKevin On 2019/9/3
**/
public class Cloth {
private Color color;
public Cloth() {
color = StaticColorFactory.newInstance();
}
//省略setter/getter方法
}
/**
* 静态工厂方法
* Created by OKevin On 2019/9/3
**/
public class StaticColorFactory {
public static Color getInstance() {
return new Red();
}
}
如果我们在Spring容器中要通过静态工厂方法,创建具体的对象实例应该怎么做呢?
众所周知,要将一个对象实例交由Spring容器管理,我们通常是通过以下XML配置:
<bean id="cloth" class="com.coderbuff.bean.Cloth">
<property name="color" ref="red"/>
</bean>
<bean id="red" class="com.coderbuff.bean.Red" />
但此时,Red对象实例并不是由Spring容器管理,而是由静态工厂方法创建的,此时我们应该讲XML配置修改为以下方式:
<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" />
这是Spring支持静态工厂方法创建对象实例的特定方式。这样我们就能在Spring中通过静态工厂方法创建对象实例。
实例工厂方法
有静态工厂方法,就有非静态工厂方法,区别就是方法不是静态的。
/**
* 实例工厂方法
* Created by OKevin On 2019/9/3
**/
public class ColorFactory {
public Color getInstance() {
return new Red();
}
}
实例工厂方法在Spring中XML配置略有不同:
<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"/>
通过配置可以看到,我们需要首先在Spring中实例化工厂,再通过工厂对象实例化Red对象。
在有了对工厂方法在Spring中创建对象实例的认识后,FactoryBean实际上就是为我们简化这个操作。下面我们将通过FactoryBean来创建Red对象。
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;
}
}
通过实现FactoryBean的方式,XML配置如下:
<bean id="cloth" class="com.coderbuff.bean.Cloth">
<property name="color" ref="red"/>
</bean>
<bean id="red" class="com.coderbuff.factory.ColorFactoryBean"/>
这样就不用像工厂方法那样配置相应的属性,直接按照普通的Bean注入即可,由于Spring内部做了特殊处理,此时名称为“red”的Bean并不是ColorFactoryBean,而是它方法中getObject中返回的对象。如果实在想要获取ColorFactoryBean的对象实例,则在Bean的名称前加入“&”即可(“&red”)。
看到这里,是否对FactoryBean有了一点认识呢?FactoryBean在Spring中最为典型的一个应用就是用来创建AOP的代理对象。
我们知道AOP实际上是Spring在运行时创建了一个代理对象,也就是说这个对象,是我们在运行时创建的,而不是一开始就定义好的,这很符合工厂方法模式。更形象地说,AOP代理对象通过Java的反射机制,在运行时创建了一个代理对象,在代理对象的目标方法中根据业务要求织入了相应的方法。这个对象在Spring中就是——ProxyFactoryBean。
ProxyFactoryBean
我们将通过比较“古老”的方式创建一个Red对象的切面,在它的print方法执行前和执行后分别执行一条语句。之所以古老是因为我们往往通过注解的方式,而不会这么折磨自己去写一个切面对象。
/**
* 环绕通知
* Created by OKevin On 2019/9/4
**/
public class LogAround implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("调用目标方法【前】打印日志");
Object result = invocation.proceed();
System.out.println("调用目标方法【后】打印日志");
return result;
}
}
此时我们需要ProxyFactoryBean的介入为我们创建一个代理对象并由Spring容器管理,根据上面ColorFactoryBean的经验,ProxyFacoryBean也应该如下配置:
<bean id="xxx" class="org.springframework.aop.framework.ProxyFactoryBean" />
答案是肯定的,只是ProxyFactoryBean多了几个参数,既然是生成代理对象,那么目标对象、目标方法就必不可少,实际的XLM配置如下:
<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>
通过测试程序,ProxyFactoryBean的确生成了一个代理对象。
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();
}
}
所以,FactoryBean为我们实例化Bean提供了一个更为灵活的方式,我们可以通过FactoryBean创建出更为复杂的Bean实例。
本文完整代码地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/factorybean

Spring中老生常谈的FactoryBean的更多相关文章
- Spring中BeanFactory与FactoryBean的区别
在Spring中有BeanFactory和FactoryBean这2个接口,从名字来看很相似,比较容易搞混. 一.BeanFactory BeanFactory是一个接口,它是Spring中工厂的顶层 ...
- 【Java面试】Spring中 BeanFactory和FactoryBean的区别
一个工作了六年多的粉丝,胸有成竹的去京东面试. 然后被Spring里面的一个问题卡住,唉,我和他说,6年啦,Spring都没搞明白? 那怎么去让面试官给你通过呢? 这个问题是: Spring中Bean ...
- spring中BeanFactory和FactoryBean的区别
共同点: 都是接口 区别: BeanFactory 以Factory结尾,表示它是一个工厂类,用于管理Bean的一个工厂 在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器 ...
- Spring中BeanFactory与FactoryBean到底有什么区别?
一.BeanFactory BeanFactory是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定义了getBean().containsBean()等管理Bea ...
- Spring学习笔记——Spring中的BeanFactory与FactoryBean
BeanFactory BeanFactory是Spring的org.springframework.beans.factory下的一个接口,是Spring IOC所遵守的基本编程规范.他的实现类有D ...
- Spring中的FactoryBean
从SessionFactory说起: 在使用SSH集成开发的时候,我们有时候会在applicationContext.xml中配置Hibernate的信息,以下是配置SessionFactory的一段 ...
- spring中的BeanFactory和FactoryBean的区别与联系
首先,这俩都是个接口… 实现 BeanFactory 接口的类表明此类是一个工厂,作用就是配置.新建.管理 各种Bean. 而 实现 FactoryBean 的类表明此类也是一个Bean,类型为工厂B ...
- 理解spring中的BeanFactory和FactoryBean的区别与联系
原文地址:http://blog.csdn.net/joenqc/article/details/66479154 首先,这俩都是个接口… 实现 BeanFactory 接口的类表明此类事一个工厂,作 ...
- Spring中FactoryBean的作用和实现原理
BeanFactory与FactoryBean,相信很多刚翻看Spring源码的同学跟我一样很好奇这俩货怎么长得这么像,分别都是干啥用的.BeanFactory是Spring中Bean工厂的顶层接口, ...
随机推荐
- 通过OpenGL理解前端渲染原理(1)
一.OpenGL OpenGL,是一套绘制3D图形的API,当然它也可以用来绘制2D的物体.OpenGL有一大套可以用来操作模型和图片的函数,通常编写OpenGL库的人是显卡的制造者.我们买的显卡都支 ...
- 遇见Python集合类型
Python目前有两种内置集合类型,set和frozenset. Ⅰ.两者区别 set是可变的,没有哈希值,其内容可以使用add()和remove()这样的方法来改变,所以不能被用作字典的键或其他集合 ...
- JDK的命令行工具系列 (二) javap、jinfo、jmap
javap: 反编译工具, 可用来查看java编译器生成的字节码 参数摘要: -help 帮助 -l 输出行和变量的表 -public 只输出public方法和域 -protected 只输出publ ...
- 给最近正在找工作(iOS)的朋友一些建议/经验
众所周知, iOS开发找工作越来越难, 企业要求越来越高,一方面是资本寒冬期+七八月是企业招人淡季, 另外一方面也是iOS市场饱和.最近有出去看新机会, 所以下面记录一下面试XimalayaFM的大概 ...
- WebRTC:一个视频聊天的简单例子
相关API简介 在前面的章节中,已经对WebRTC相关的重要知识点进行了介绍,包括涉及的网络协议.会话描述协议.如何进行网络穿透等,剩下的就是WebRTC的API了. WebRTC通信相关的API非常 ...
- 浅谈 ASCII、Unicode、UTF-8,一目了然
对于ASCII.Unicode.UTF-8这三种编码方式我们经常用到,也经常挂到嘴边,但他们是怎么来的,为什么要存在,具体是怎么个规则,我们并没有做深入了解,下面,就带你看一下他们到底是怎么回事吧…… ...
- 9-2、大型项目的接口自动化实践记录----递归判断两个json串是否相等
1.已知json串构成的情况下判断 先构造一下场景,假设已经把各个数据都移除掉不对比的字段 图1 预期.实际结果,复杂接口返回多层嵌套json时,同下 图2 预期.实际结果值为:{child_json ...
- win7 python pdf2image入坑经历
Python开发菜鸟入坑 项目要求pdf转成图片,网上较多的方案对于windows极其不友好,wand,Pythonmagick(win下载地址:www.lfd.uci.edu/~gohlke/pyt ...
- .NET Core 3.0预览版7中的ASP.NET Core和Blazor更新
.NET Core 3.0 Preview 7现已推出,它包含一系列ASP.NET Core和Blazor的新更新. 以下是此预览中的新功能列表: 最新的Visual Studio预览包括.NET C ...
- 又拍云叶靖:OpenResty 在又拍云存储中的应用
2019 年 7 月 6 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙·上海站,又拍云平台开发部负责人叶靖在活动上做了<OpenRest ...