Spring通过工厂创建实例的注意事项

假设第三方(or别的team)提供一个工厂类(此类是不能够改动的。往往以jar包形式提供的),须要供给我们项目来使用。

可是我们自己的项目使用了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;
		}
	}

}

介绍如上工厂类的特殊性:

  1. 全部的方法属性都是静态的。
  2. setEnv() 是静态方法:内部是往静态属性props设值。
  3. 两个工厂方法。是静态空參方法(这是符合工厂方法定义的)。内部的实现是依据已经设置好的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会失败!原因:

  1. spring尽管会调用setEnv()方法。可是并非调用x.y.ClientFactory类里面的此方法,而是调用internalClient实例里面的setEnv()方法。

    所以此<property>的配置是无效的。

  2. 另外工厂方法getIntenalCmdClient会被首先调用(能够debug断点),然后spring再调用setEnv方法。因此在调用getIntenalCmdClient时候没有不论什么env參数被传入。
  3. 以上两条都会导致实例化失败。

二:会有人说既然“静态工厂化方法”不可取,那么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会失败!原因:

  1. 实例化clientFactory,其目的是为了让spring调用setEnv方法。往x.y.ClientFactory类里面设值(静态属性env设值),由于设置了factory-bean属性。所以clientFactory的实例化顺序会先于internalClient。到眼下没有什么问题。可是问题出如今第二点
  2. 工厂方法gentIntenalCmdClient是静态方法。设置了factory-bean属性的含义就是clientFactory.getIntenalCmdClient如此调用,在spring里面不支持对象引用静态方法!因此是报错的。
  3. 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.”

综上两种情况。我想出了解决方法。

  1. 实例化clientFactory bean还是需要的,由于必需要保证env能够最先set值(静态方法setEnv()能够最先被调用)。
  2. 实例化internalClient bean使用"静态工厂方法"。如此就能够成功的调用静态工厂方法(ClientFactory.getIntenalCmdClient())
  3. 为保证先setEnv,再调用工厂方法(ClientFactory.getIntenalCmdClient()),能够使用depends-on属性
  4. 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:

实例工厂和静态工厂一样的同样限制:

  1. 静态工厂方法上不能有參数,也不能在Spring种定义静态工厂方法的參数。

  2. 静态工厂方法仅仅能是public的,不能是private或protected的。

  3. 静态工厂方法不能和构造函数注入一起使用。

实例工厂和静态工厂不同的点:

  • 实例工厂方法不能是静态的,而静态工厂方法必须是静态的。
时间: 2024-10-14 10:15:00

Spring通过工厂创建实例的注意事项的相关文章

4.spring对象的创建(静态工厂 实例工厂 泛型,嵌套类型)

1.原料类 namespace CreateObjects{    public class GenericClass<T>    { }} PersonDao 类 包含嵌套类型 namespace CreateObjects{    public class PersonDao    {        public class Person         {            public override string ToString()            {         

Spring基础(3) : 静态工厂和实例工厂创建bean

public class Factory { public static Person staticCreate(){ Person p = new Person(); p.name="staticCreate"; return p; } public Person instanceCreate(){ Person p = new Person(); p.name="instanceCreate"; return p; } } public static void

关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-使用工厂创建代理(Using the ProxyFactoryObject to create AOP proxies)

本文翻译自Spring.NET官方文档Version 1.3.2. 受限于个人知识水平,有些地方翻译可能不准确,但是我还是希望我的这些微薄的努力能为他人提供帮助. 侵删. 如果你正在为你的业务模型使用IoC容器--这是个好主意--你将会想使用某个 Spring.NET's AOP特定的IFactoryObject 的实现(要记住,一个工厂的实例提供了一个间接层,使这个工厂能够创建不同类型的对象-5.3.9节,"通过使用其他类型和实例创建一个对象"). 一个基本的创建Spring.NET

传统抽象工厂(通过反射来创建实例)-》目的为了解耦

//第一步创建一个AbstractFactory类,在这个类里面定义两个静态属性:AssemblyPath ,NameSpace //第二步在工厂类里面写一个静态方法:public static IUserInfoDal CreateUserInfoDal(){}//第三步再写一个方法:private static object CreateInstance(string fullName)通过Assembly反射来创建实例//第四步在web.config文件下配置这两个静态属性:Assembl

activiti自定义流程之Spring整合activiti-modeler5.16实例(二):创建流程模型

注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 1.maven导包,这里就没有什么多的好说了,直接代码: [html] view plain copy <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11&

Spring 通过工厂方法(Factory Method)来配置bean

Spring 通过工厂方法(Factory Method)来配置bean 在Spring的世界中, 我们通常会利用bean config file 或者 annotation注解方式来配置bean. 在第一种利用bean config file(spring xml)方式中, 还包括如下三小类 反射模式 工厂方法模式(本文重点) Factory Bean模式 其中反射模式最常见, 我们需要在bean 配置中指明我们需要的bean object的全类名. 例如: <bean id="car1

Spring笔记——4.创建Bean的三种方式

Spring支持使用如下三种方法创建Bean: 调用构造器创建Bean 调用静态工厂方法创建Bean 调用实例工厂方法创建Bean 构造器 这是最常见的,框架底层调用bean的无参数构造器.这种情况下,class助兴是必需的.之前写的都是这种方式. 静态工厂方法创建Bean class也必须指定,但不是指定实现类,而是静态工厂类,这个工厂会创建bean实例.另外还需要factory-method指定用哪个方法创建bean实例,返回值即为实例. 接口与实现类如下: public interface

spring 通过工厂方法配置Bean

概要: 通过调用静态工厂方法创建Bean 调用静态工厂方法创建Bean是将对象创建的过程封装到静态方法中.当client须要对象时,仅仅须要简单地调用静态方法,而不用关心创建对象地细节. 要声明通过静态方法创建的Bean,须要在Bean地class属性里指定拥有该工厂的方法的类,同一时候在factory-method属性里指定工厂方法的名称.最后,使用<constructor-arg>元素为该方法传递方法參数 通过调用实例工厂方法创建Bean 实例工厂方法:将对象的创建过程封装到另外一个对象实

由spring的工厂构造bean想到的

被Spring管理的bean可以是直接创建实例,还可以通过工厂模式来进行创建.例如brave的tracing bean定义: 1 <bean id="tracing" class="brave.spring.beans.TracingFactoryBean"> 2 ... 3 <property name="propagationFactory"> 4 <bean id="propagationFactor