Spring通过工厂创建实例的注意事项
2016-01-23 17:21
232 查看
假设第三方(or别的team)提供一个工厂类(此类是不能够改动的。往往以jar包形式提供的),须要供给我们项目来使用。
可是我们自己的项目使用了spring来配置,所以我们当然希望可以通过spring的aop来配置这个工厂类来,来创建实例以进行引用。
可是这个工厂类的源码比較特殊。例如以下:
介绍如上工厂类的特殊性:
全部的方法属性都是静态的。
setEnv() 是静态方法:内部是往静态属性props设值。
两个工厂方法。是静态空參方法(这是符合工厂方法定义的)。内部的实现是依据已经设置好的props来实例化对象,假设參数(env)没有设值,那么实例化对象就会失败。所以我们就须要先setEnv,在通过工厂方法实例化对象。
一:有人会说,这个非常easy。依据spring的官方文档。用“静态工厂方法”进行实例化。
可是此方法不可取,例如以下所述:
如上配置。实例化internalClient会失败!原因:
spring尽管会调用setEnv()方法。可是并非调用x.y.ClientFactory类里面的此方法,而是调用internalClient实例里面的setEnv()方法。
所以此<property>的配置是无效的。
另外工厂方法getIntenalCmdClient会被首先调用(能够debug断点),然后spring再调用setEnv方法。因此在调用getIntenalCmdClient时候没有不论什么env參数被传入。
以上两条都会导致实例化失败。
二:会有人说既然“静态工厂化方法”不可取,那么spring官方文档里面还提供了“实例工厂方法”。可是此方法也是不可取的,例如以下所述:
如上配置。实例化internalClient会失败!原因:
实例化clientFactory,其目的是为了让spring调用setEnv方法。往x.y.ClientFactory类里面设值(静态属性env设值),由于设置了factory-bean属性。所以clientFactory的实例化顺序会先于internalClient。到眼下没有什么问题。可是问题出如今第二点
工厂方法gentIntenalCmdClient是静态方法。设置了factory-bean属性的含义就是clientFactory.getIntenalCmdClient如此调用,在spring里面不支持对象引用静态方法!因此是报错的。
spring报错log:“No matching factory method found: factory bean 'clientFactory'; factory method 'getIntenalCmdClient()'. Check that a method with the specified name exists and that it is non-static.”
综上两种情况。我想出了解决方法。
实例化clientFactory bean还是需要的,由于必需要保证env能够最先set值(静态方法setEnv()能够最先被调用)。
实例化internalClient bean使用"静态工厂方法"。如此就能够成功的调用静态工厂方法(ClientFactory.getIntenalCmdClient())
为保证先setEnv,再调用工厂方法(ClientFactory.getIntenalCmdClient()),能够使用depends-on属性
destroy-method所设值的方法。是internalClient实例所能引用到的方法。
配置例如以下:
如有不正确的or更好的解决方式,望大哥赐教!
BTW:
实例工厂和静态工厂一样的同样限制:
静态工厂方法上不能有參数,也不能在Spring种定义静态工厂方法的參数。
静态工厂方法仅仅能是public的,不能是private或protected的。
静态工厂方法不能和构造函数注入一起使用。
实例工厂和静态工厂不同的点:
实例工厂方法不能是静态的,而静态工厂方法必须是静态的。
可是我们自己的项目使用了spring来配置,所以我们当然希望可以通过spring的aop来配置这个工厂类来,来创建实例以进行引用。
可是这个工厂类的源码比較特殊。例如以下:
package x.y; import java.util.Properties; import x.y.client.CmdClient; import x.y.client.InternalCmdClient; public class ClientFactory { private static volatile CmdClient cmdclient; private static volatile InternalCmdClient cmdinternalclient; private static Properties props = new Properties(); public static void setEnv(String env){ props.put( "env", env ); } public static CmdClient getCmdClient() throws Exception{ if ( cmdclient == null ) { synchronized ( CmdClientImpl.class ) { if ( cmdclient == null ) { cmdclient = new CmdClientImpl( props ); } } } return cmdclient; } public static InternalCmdClient getIntenalCmdClient() throws Exception{ if ( cmdinternalclient == null ) { synchronized ( InternalCmdClientImpl.class ) { if ( cmdinternalclient == null ) { cmdinternalclient = new InternalCmdClientImpl( props ); } } } return cmdinternalclient; } public static void destoryClient(){ if ( cmdclient != null ) { cmdclient.destroy(); cmdclient = null; } if ( cmdinternalclient != null ) { cmdinternalclient.destroy(); cmdinternalclient = null; } } }
介绍如上工厂类的特殊性:
全部的方法属性都是静态的。
setEnv() 是静态方法:内部是往静态属性props设值。
两个工厂方法。是静态空參方法(这是符合工厂方法定义的)。内部的实现是依据已经设置好的props来实例化对象,假设參数(env)没有设值,那么实例化对象就会失败。所以我们就须要先setEnv,在通过工厂方法实例化对象。
一:有人会说,这个非常easy。依据spring的官方文档。用“静态工厂方法”进行实例化。
可是此方法不可取,例如以下所述:
<bean id="internalClient" class="x.y.ClientFactory" factory-method="getIntenalCmdClient" destroy-method="destroy"> <property name="env" value="${env}" /> </bean>
如上配置。实例化internalClient会失败!原因:
spring尽管会调用setEnv()方法。可是并非调用x.y.ClientFactory类里面的此方法,而是调用internalClient实例里面的setEnv()方法。
所以此<property>的配置是无效的。
另外工厂方法getIntenalCmdClient会被首先调用(能够debug断点),然后spring再调用setEnv方法。因此在调用getIntenalCmdClient时候没有不论什么env參数被传入。
以上两条都会导致实例化失败。
二:会有人说既然“静态工厂化方法”不可取,那么spring官方文档里面还提供了“实例工厂方法”。可是此方法也是不可取的,例如以下所述:
<bean id="clientFactory" class="x.y.ClientFactory"> <property name="env" value="${env}" /> </bean> <bean id="internalClient" factory-bean="clientFactory" factory-method="getIntenalCmdClient" destroy-method="destroy"> </bean>
如上配置。实例化internalClient会失败!原因:
实例化clientFactory,其目的是为了让spring调用setEnv方法。往x.y.ClientFactory类里面设值(静态属性env设值),由于设置了factory-bean属性。所以clientFactory的实例化顺序会先于internalClient。到眼下没有什么问题。可是问题出如今第二点
工厂方法gentIntenalCmdClient是静态方法。设置了factory-bean属性的含义就是clientFactory.getIntenalCmdClient如此调用,在spring里面不支持对象引用静态方法!因此是报错的。
spring报错log:“No matching factory method found: factory bean 'clientFactory'; factory method 'getIntenalCmdClient()'. Check that a method with the specified name exists and that it is non-static.”
综上两种情况。我想出了解决方法。
实例化clientFactory bean还是需要的,由于必需要保证env能够最先set值(静态方法setEnv()能够最先被调用)。
实例化internalClient bean使用"静态工厂方法"。如此就能够成功的调用静态工厂方法(ClientFactory.getIntenalCmdClient())
为保证先setEnv,再调用工厂方法(ClientFactory.getIntenalCmdClient()),能够使用depends-on属性
destroy-method所设值的方法。是internalClient实例所能引用到的方法。
配置例如以下:
<bean id="internalClient" class="x.y.AhClientFactory" factory-method="getIntenalCmdClient" destroy-method="destroy" depends-on="clientFactory"> </bean> <bean id="clientFactory" class="x.y.ClientFactory"> <property name="env" value="${env}" /> </bean>
如有不正确的or更好的解决方式,望大哥赐教!
BTW:
实例工厂和静态工厂一样的同样限制:
静态工厂方法上不能有參数,也不能在Spring种定义静态工厂方法的參数。
静态工厂方法仅仅能是public的,不能是private或protected的。
静态工厂方法不能和构造函数注入一起使用。
实例工厂和静态工厂不同的点:
实例工厂方法不能是静态的,而静态工厂方法必须是静态的。
相关文章推荐
- Ehcache是现在最流行的纯Java开源缓存框架
- JavaSE-接口之静态代理模式
- 整合Struts2与Spring
- Java之接口
- 运行时数据区域
- java数据库连接JDBC
- 编码规范系列(二):Eclipse Checkstyle配置
- 编码规范系列(一):Eclipse Code Templates设置
- JavaSE-接口之工厂方法的设计
- 轻量级的Java 开发框架 Spring
- struts2基于Convention插件的约定映射使用
- Java基础加强
- JavaEmail
- Java 对象的强引用、软引用、弱引用和虚引用
- 通过内省机制设置JavaBean
- Java 对象与垃圾回收
- Spring 4.1.7 MVC @RequestPart 问题
- java中IO流的学习笔记(2、复制数据)
- java中protected的权限
- 王立平--eclipse向svnserver上传项目