工厂方法与 FactoryBean
引子
直接依赖接口实现类的类Foo
:
public class Foo { private BarInterface barInstance; public Foo() { // 我们应该避免这样做// instance = new BarInterfaceImpl(); } // ... 复制代码
使用了工厂方法模式的Foo
类可能定义:
public class Foo { private BarInterface barInterface; public Foo() { // barInterface = BarInterfaceFactory.getInstance(); // 或者 // barInterface = new BarInterfaceFactory().getInstance(); } ... 复制代码
此时接口BarInterface
与BarInterfaceImpl
解耦,BarInterface
与 BarInterfaceFactory
耦合,实现了替换BarInterface
实现类只需要替换BarInterfaceFactory
持有的实现类即可。
静态工厂方法(Static Factory Method)
不带参数的静态工厂方法:
静态工厂类:
public class StaticBarInterfaceFactory { public static BarInterface getInstance() { return new BarInterfaceImpl(); } } 复制代码
为Foo
注入BarInterface
的XML配置:
复制代码
其中,barInterface
的注入方式为setter
注入,为Foo
类实例注入了BarInterfaceImpl
的实例。且此处的id="bar"
的bean指的是通过StaticBarInterfaceFactory
的getInstance
方法获得的BarInterfaceImpl
实例。
注意
id="bar"
的bean属性factory-method
和class
的作用
带参数的静态工厂方法:
静态方法带参数的静态工厂类:
public class StaticBarInterfaceFactory { public static BarInterface getInstance(Foobar foobar) { return new BarInterfaceImpl(foobar); } } 复制代码
为Foo注入 BarInterface 的XML配置:
复制代码
具体参数的使用在BarInterfaceImpl中实现,同上,此处的id="bar"的bean指的是通过 StaticBarInterfaceFactory 的 getInstance 方法获得的 BarInterfaceImpl 实例,构造参数foobar也是传递给BarInterfaceImp的。
注意
<constructor-arg>
节点的作用
非静态工厂方法(Instance Factory Method)
非静态方法工厂类:
public class NonStaticBarInterfaceFactory { public BarInterface getInstance() { return new BarInterfaceImpl(); } ... 复制代码
为Foo注入 BarInterface 的XML配置:
复制代码
此处的工厂类作为普通bean注册到Spring容器中,而不是直接调用静态方法(需要实例化才能调用实例方法)。
如果非静态工厂方法调用时也需要提供参数的话,处理方式是与静态的工厂方法相似的,都可以通过<constructor-arg>
来指定方法调用参数。 注意
factory-bean
属性的作用。
FactoryBean
FactoryBean是Spring容器提供的一种可以扩展容器对象实例化逻辑的接口,请不要将其与容器名称BeanFactory相混淆。它的实现类是专用于生产对象的bean。
当某些对象的实例化过程过于烦琐,通过XML配置过于复杂,使我们宁愿使用Java代码来完成这 个实例化过程的时候,或者,某些第三方库不能直接注册到Spring容器的时候,就可以实现org.spring.framework.beans.factory.FactoryBean
接口,给出自己的对象实例化逻辑代码。 FactoryBean定义:
public interface FactoryBean { //返回产品类对象 Object getObject() throws Exception; //返回产品类类型 Class getObjectType(); //返回产品类scope boolean isSingleton(); } 复制代码
每次得到的日期都是第二天工厂实现类:
import org.joda.time.DateTime; import org.springframework.beans.factory.FactoryBean; public class NextDayDateFactoryBean implements FactoryBean { public Object getObject() throws Exception { return new DateTime().plusDays(1); } public Class getObjectType() { return DateTime.class; } public boolean isSingleton() { return false; } } 复制代码
将NextDayDateFactoryBean
注册到Spring容器:
复制代码
注意
id="nextDayDate"
的bean没有使用factory-method
属性就完成了依赖对象的生产,这里是FactoryBean
接口的作用。
NextDayDateDisplayer
类定义:
public class NextDayDateDisplayer { private DateTime dateOfNextDay; // 相应的setter方法 // ... } 复制代码
由此,我们实现了NextDayDateDisplayer
不依赖NextDayDateFactoryBean
即可得到依赖的DateTime
实例,即Spring容器通过工厂模式实现了类依赖注入。
使用&
获取FactoryBean
的实例演示:
//以下所有assert均通过//获取工厂产品类DateTimeObject nextDayDate = container.getBean("nextDayDate"); assertTrue(nextDayDate instanceof DateTime);//获取FactoryBean类的对象本身Object factoryBean = container.getBean("&nextDayDate"); assertTrue(factoryBean instanceof FactoryBean); assertTrue(factoryBean instanceof NextDayDateFactoryBean); //通过上一步获得的FactoryBean获取工厂产品类DateTime的对象Object factoryValue = ((FactoryBean)factoryBean).getObject(); assertTrue(factoryValue instanceof DateTime); assertNotSame(nextDayDate, factoryValue); assertEquals(((DateTime)nextDayDate).getDayOfYear(),((DateTime)factoryValue).getDayOfYear()); 复制代码
Spring容器使用FactoryBean
案例:
JndiObjectFactoryBean
LocalSessionFactoryBean
SqlMapClientFactoryBean
ProxyFactoryBean
TransactionProxyFactoryBean