使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用

希望能实现一个对象池,但是同时要避免调用returnObject。
因为如果可以避免调用returnObject,那么就原来的代码就可以不做修改就能使用对象池优化功能了。

下面是为了实现上述功能写的示例代码。

先声明一点,准备保存到池里面的对象是不用在两次调用之间保存状态的。
所以下面的示例代码中,每次调用一个方法的时候,都从池里面找一个对象,用完之后,立即归还。
所以原来的代码中,每次使用对象的时候,从工厂里面new一个对象出来,使用完了也不做任何处理。
类似如下代码。


....
SamplePortType obj = new SampleClass();
obj.helloWorld();
....

另外,由于是示例代码,所以里面涉及多线程同步的问题也做处理。

代码虽然写了出来,就这个示例程序来说,也能跑了,
但是对其中的实现方法存在一些疑问。

主要的疑问是,示例代码中,Proxy.newProxyInstance 每次都是使用同样的一个对象来创建动态代理,
然后实际invoke(Object proxy, Method method, Object[] args)的时候,使用另外一个对象去执行。
不知道这样做会不会存在问题?

不知道为了实现刚开始提出的问题,有什么其他办法?


import java.util.logging.*;
import java.util.Stack;
import java.lang.reflect.*;
import java.lang.Object;
import java.lang.System;

interface SamplePortType {
public void helloWorld ( );
};

class SampleClass implements SamplePortType {
public SampleClass ( ) { }
public void helloWorld ( ) {
System.out.println ( "Hello world!" );
}
};

class SamplePool {
static private SamplePool _instance;
static public SamplePool getInstance() {
if ( null == _instance ) {
_instance = new SamplePool();
}
return _instance;
}

private SamplePool ( ) { _pool = new Stack(); }

public SamplePortType borrowObject ( ) {
if ( _pool.empty() ) {
return new SampleClass();
} else {
return (SamplePortType)_pool.pop();
}
}

public void returnObject ( SamplePortType obj ) { _pool.push ( obj ); }

private Stack _pool;
};

public class AOPHandler implements InvocationHandler {
static private SamplePortType _orgObject = null;

public static SamplePortType getObject ( ) {
if ( null == _orgObject ) _orgObject = new SampleClass();
return (SamplePortType)Proxy.newProxyInstance(
_orgObject.getClass().getClassLoader(),
_orgObject.getClass().getInterfaces(),
new AOPHandler() );
}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {

SamplePortType obj = SamplePool.getInstance().borrowObject();
Object result = null;
result = method.invoke(obj, args);
SamplePool.getInstance().returnObject ( obj );
return result;
}

static public void main ( String args[] ) {
SamplePortType obj = AOPHandler.getObject();
obj.helloWorld ( );
}
}

上面的描述有些错别字,论坛好像没有办法对已经发表的帖子做修改,所以在这里加以说明一下:

1.所以原来的代码中,每次使用对象的时候,从工厂里面new一个对象出来,使用完了也不做任何处理。
类似如下代码。


....
SamplePortType obj = SampleFactory.getObject();
obj.helloWorld();
....

2.另外,由于是示例代码,所以里面涉及多线程同步的问题也“没”做处理。

转贴一篇类似的讨论


☆─────────────────────────────────────☆
gty (宜良-丽江-蝴蝶泉) 于 (Fri Feb 21 02:33:56 2003) 提到:

Session Pool Design

1. 利用apache common-pool实现一个Session Pool(非常简单)
2. 如何避免代码中的returnObject()?

xxx() invoke
--------> PoolProxy ---> PoolInterceptor SessionPool
borrowObject()
--------------->
<---------------


xxx() Session (be borrowed)
-------------------------------->

returnObject()
---------------->



☆─────────────────────────────────────☆
gty (宜良-丽江-蝴蝶泉) 于 (Fri Feb 21 02:38:01 2003) 提到:

RMI design

xxx() invoke Serialize call to remote
-----> ClientProxy ---> RmiInterceptor ------------------->

find ServerProxy, xxx() xxx()
RmiServer----------------> ServerProxy --->....-->ServerObject



☆─────────────────────────────────────☆
gty (宜良-丽江-蝴蝶泉) 于 (Fri Feb 21 02:43:37 2003) 提到:

Method Cache design

1.用HashMap做cache

xxx() invoke
-----> Proxy ---> MCInterceptor
1. get Attribute @timeout
2. 用object[]作为key,看cache中的
结果是否超时

3. 如果超时 invoke
------------------> NextInterceptor...
4. 如果不超,返回被cache的结果



☆─────────────────────────────────────☆
gty (宜良-丽江-蝴蝶泉) 于 (Fri Feb 21 02:47:03 2003) 提到:

Draw activity UML diagram:

1. 实现绘图模块
xxx() invoke
---> Proxy ---> ActivityIntercpetor
draw xxx()
--------------->绘图模块
invoke
--------------------------->NextInterceptor...



☆─────────────────────────────────────☆
gty (宜良-丽江-蝴蝶泉) 于 (Fri Feb 21 02:53:04 2003) 提到:

Persistence and descriptive transaction

1. Persistence直接使用hibernate


xxx invoke
---->Proxy-->HibernateInterceptor
1. 取得@tx,应该为required,requiresnew
,supports,notsupported中的一种
2. 判断当前的transaction状态
3. 决定本次调用是否在transaction当中



☆─────────────────────────────────────☆
gty (宜良-丽江-蝴蝶泉) 于 (Fri Feb 21 03:01:18 2003) 提到:

Folder-Node关系的复用


getFolder() getFolder() invoke getFolder()
--->UserProxy ------> NodeProxy -->SideEntityInterceptor--> Node
return Folder
<-----
根据Folder创建Group proxy
返回GroupProxy
<----


in the code, like this:

...
User user = userFactory.find("guty"); //user is actually a proxy
Group group = (Group)((Node)user).getFolder();

为什么创建动态代理的时候,对象不从pool中去取呢?另外对象池为什么要用堆栈处理,我觉得用HashSet这样的随机顺序比较好。
public static SamplePortType getObject2() {
SamplePortType _orgObject = SamplePool.getInstance().borrowObject();
return (SamplePortType) Proxy.newProxyInstance(
_orgObject.getClass().getClassLoader(),
_orgObject.getClass().getInterfaces(),
new AOPHandler());
}

这样处理的话,都是随机的了。

或者更加简洁安全的做法:
public static SamplePortType getObject2() {
SamplePortType _orgObject = new SamplePortType(){
public void helloWorld (){}
};
return (SamplePortType) Proxy.newProxyInstance(
_orgObject.getClass().getClassLoader(),
_orgObject.getClass().getInterfaces(),
new AOPHandler());
}

1.这里的代码都是示例代码,所以pool里面使用stack只是临时的选择。
为了能写一个很小的程序,并且随手copy paste之后,
用javac命令行就能跑起来看结果。
真正用的时候,考虑使用apache的common-pool。

2.上面的代码写的不够清晰,改为如下所示。
注意, _orgObject 是static的。
而这个也正是存在疑问的地方。
应为 _orgObject 是 static 的,所以通过 AOPHandler.getObject
返回的每个 动态代理 对象包含的都是同一个 _orgObject。
不知道这样做有没有问题?


public class AOPHandler implements InvocationHandler {
static private SamplePortType _orgObject = new SampleClass();

public static SamplePortType getObject ( ) {
return (SamplePortType)Proxy.newProxyInstance(
_orgObject.getClass().getClassLoader(),
_orgObject.getClass().getInterfaces(),
new AOPHandler() );
}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {

SamplePortType obj = SamplePool.getInstance().borrowObject();
Object result = null;
result = method.invoke(obj, args);
SamplePool.getInstance().returnObject ( obj );
return result;
}

static public void main ( String args[] ) {
SamplePortType obj = AOPHandler.getObject();
obj.helloWorld ( );
}
}

之前没详细看 jdk 的文档,只看了一个别人写的例子,以为
Proxy.newProxyInstance的时候一定要有一个对象实例,
后来看了 jdk 的文档,其实不需要有一个实例就可以
Proxy.newProxyInstance了。


public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler h)
throws IllegalArgumentException

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);

多谢banq的提示,现在重写了一下代码,如下所示。


import java.util.logging.*;
import java.util.Stack;
import java.lang.reflect.*;
import java.lang.Object;
import java.lang.System;

interface SamplePortType {
public void helloWorld ( );
};

class SampleClass implements SamplePortType {
public SampleClass ( ) { }
public void helloWorld ( ) {
System.out.println ( "Hello world!" );
}
};

class SamplePool {
static private SamplePool _instance;
static public SamplePool getInstance() {
if ( null == _instance ) {
_instance = new SamplePool();
}
return _instance;
}

private SamplePool ( ) { _pool = new Stack(); }

public SamplePortType borrowObject ( ) {
if ( _pool.empty() ) {
return new SampleClass();
} else {
return (SamplePortType)_pool.pop();
}
}
public void returnObject ( SamplePortType obj ) { _pool.push ( obj ); }

private Stack _pool;
};

public class AOPHandler implements InvocationHandler {

public static SamplePortType getObject ( ) {
return (SamplePortType)Proxy.newProxyInstance(
SamplePortType.class.getClassLoader(),
SampleClass.class.getInterfaces(),
//SamplePortType.class.getInterfaces(),
new AOPHandler() );
}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {

SamplePortType obj = SamplePool.getInstance().borrowObject();
Object result = null;
try {
result = method.invoke(obj, args);
} finally {
SamplePool.getInstance().returnObject ( obj );
}

return result;
}

static public void main ( String args[] ) {
SamplePortType obj = AOPHandler.getObject();
obj.helloWorld ( );
}
}




你的代码我觉得可以,invoke方法要做一些Catch就更成熟,
这样执行出错时也可以returnObject。

你这个例子其实是使用动态代理实现AOP的一个实例。

使用AOP的思路,可以彻底将对象池和应用程序分离开,
客户端调用PetshopServiceTarget,只要调用getBean(“businessObject”)即可,
实际就是从对象池中获取的。
以Spring的例程Petshop,在其中主要配置:



<bean id=“poolTargetSource“
class=“spring.CommonsPoolTargetSource">
<property name=
"targetBeanName">
<value>petshopServiceTarget</value>
</property>
<property name=
"maxSize">
<value>25</value>
</property>
</bean>
<bean id=
"businessObject"
class=org.springframework.aop.framework.ProxyFactoryBean
">
<property name=
"targetSource">
<ref local=
"poolTargetSource"/>
</property>
<property name=
"interceptorNames">
<value>myInterceptor</value>
</property>
</bean>

不清楚楼主的目的是什么,下面我贴出部分我以前写的程序,和你的很类似,通过动态代理产生业务代理层,同时封装事务调用,并且采用配置文件的方式决定对象的产生方式(singleton,unlimited , poolable),
public class BeanFactory {
....
private Object getBeanProxy(BeanConfiguration config)
throws UtilException {
Object bean = null ;
Object proxy = null ;
TransactionDelegate delegate = null ;
String beanName = config.getImpl();
String[] interfaceNames = config.getName();
Class[] cls = new Class[interfaceNames.length] ;
try {
for (int i = 0; i < interfaceNames.length; i++) {
System.out.println("cls ="+interfaceNames);
cls = Class.forName(interfaceNames.trim()) ;
}
if (BeanConfiguration.SINGLETON.equals(config.getMethod())) {
bean = cache.getFromCache(beanName) ;
if (bean == null) {
bean = Class.forName(beanName).newInstance() ;
cache.putIntoCache(beanName , bean) ;
}
delegate = new TransactionDelegate() ;
delegate.setObject(bean) ;
proxy = Proxy.newProxyInstance(delegate.getClass().getClassLoader() ,
cls , delegate) ;
} else if (BeanConfiguration.UNLIMITED.equals(config.getMethod())) {
bean = Class.forName(beanName).newInstance() ;
delegate = new TransactionDelegate();
delegate.setObject(bean);
proxy = Proxy.newProxyInstance(delegate.getClass().getClassLoader() ,
cls , delegate);
} else if (BeanConfiguration.POOLED.equals(config.getMethod())) {
ServiceLog.debug("beanPool instance ="+beanPool);
if (beanPool == null) {
throw new UtilException("系统没有发现相应的池,不支持池管理Bean" , -1);
}
ServiceLog.info("current facade bean pool active num is ="+beanPool.currentActiveNum(beanName));
ServiceLog.info("current facade bean pool idle num is ="+beanPool.currentIdleNum(beanName));
bean = beanPool.get(beanName) ;
delegate = new TransactionDelegate() ;
delegate.setObject(bean);
ServiceLog.info("current facade bean pool size is ="+delegate);
proxy = Proxy.newProxyInstance(delegate.getClass().getClassLoader() ,
cls , delegate);
} else {
throw new UtilException("错误的池的Bean管理方式" , -1);
}
System.out.println("从池中取出的bean 为="+bean);
return proxy ;
} catch (UtilException ex) {
ex.printStackTrace();
ServiceLog.error(ex.getMessage() , ex);
throw ex ;
} catch (Exception ex) {
ex.printStackTrace();
ServiceLog.error(ex.getMessage() , ex);
throw new UtilException(ex);
}
}
......
}

package com.goldenchance.amis.framework.proxy;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
import com.goldenchance.common.framework.OperationService;
import com.goldenchance.common.exception.FacadeAccessException;
import com.goldenchance.common.util.TransactionContext;
import com.goldenchance.common.util.TransactionContextFactory;
import com.goldenchance.common.log.ServiceLog;
import java.util.*;
import java.lang.reflect.*;
/**
* 事务代理类
* <p>Title: 实时监控系统</p>
* <p>Description: 通过动态代理技术,实现事务处理的动态封装</p>
* @version 1.0
*/
public class TransactionDelegate implements InvocationHandler {
private final static List DEFAULT_METHOD_LIST = new ArrayList();
private TransactionContextFactory factory ;
private Object object;

public TransactionDelegate() {
factory = TransactionContextFactory.newFactory();
}

public void finalize() {
this.release();
}

public void release() {
object = null ;
}

/**
* 将Object对象中的方法设置为纳入默认忽略的方法集合中
*/
static {
DEFAULT_METHOD_LIST.add("equals");
DEFAULT_METHOD_LIST.add("getClass");
DEFAULT_METHOD_LIST.add("hashCode");
DEFAULT_METHOD_LIST.add("notify");
DEFAULT_METHOD_LIST.add("notifyAll");
DEFAULT_METHOD_LIST.add("toString");
DEFAULT_METHOD_LIST.add("wait");
}

/**
* 实现接口的invoke方法
* @see java.lang.reflect.InvocationHandler.invoke(Object , Method , Object[])
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName() ;
Object result = null ;
ServiceLog.info("开始调用"+object.getClass().getName()+"的方法"+name);
if (DEFAULT_METHOD_LIST.contains(name)) {
result = method.invoke(object , args);
ServiceLog.info("Start : 调用"+object.getClass().getName()+"的方法"+name);
return result ;
} else if (object instanceof OperationService){
//如果代理对象是OperationService实现类,则说明它支持事务处理
OperationService serivce = (OperationService)object ;
TransactionContext tc = factory.getTransactionContext();
try {
serivce.setTransactionContext(tc);
if (name.startsWith("search")) {
//如果是查询方法,则不进行事务封装
result = method.invoke(object , args) ;
} else {
tc.beginTransaction();
try {
result = method.invoke(object , args) ;
tc.commitTransaction();
} catch (Exception ex) {
ServiceLog.error(ex.getMessage() , ex) ;
if (ex instanceof FacadeAccessException) {
FacadeAccessException actual = (FacadeAccessException) ex ;
tc.rollbackTransaction() ;
throw actual ;
}
throw ex ;
}
}
return result ;
} finally {
tc.closeConnection();
ServiceLog.info("End : 调用"+object.getClass().getName()+"的方法"+name);
}

} else {
result = method.invoke(object , args) ;
return result ;
}

}

public Object getObject() {
return object;
}

public void setObject(Object object) {
this.object = object;
}

}

非常不错的动态代理程序,同时使用Cache提升了性能。
建议 Proxy.newProxyInstance这一句也采取缓存,每次调用,性能也是比较低的。

建议:BeanConfiguration.SINGLETON.equals(config.getMethod())) 这段if else重整一下,可状态模式,通过辅助类映射XML配置。

这段程序可谓是Spring这个大系统的微观,主体思路非常相似。

是啊,说白了,写这程序的思想就是来自于spring。
banq说将Proxy.newInstance也缓存起来,其实开始我也是打算如此,只是后来我发现在处理释放池中的内容时会引来一些问题,带来不必要的耦合。至于将BeanConfiguration.SINGLETON.equals(config.getMethod())) 这段改写,倒是一个不错的主意。

Jdonframework将Proxy.newInstance进行了缓存处理,缺点是引入了J2EE WEB容器。

我觉得没有必要使用动态代理. 静态的代理也能达到同样的效果.可能我对动态代理的特性掌握不够,请教一下在这里使用动态代理有什么好处?谢谢.
这里是静态代理实现:

public class AOPHandler {

static private SamplePortType _orgObject = null;

public static SamplePortType getObject ( ) {
if ( null == _orgObject )
_orgObject = new SamplePortType(){
public void helloWorld(){
SamplePortType obj = SamplePool.getInstance().borrowObject();
obj.helloWorld();
SamplePool.getInstance().returnObject( obj );
}
};

return _orgObject;
}

static public void main ( String args[] ) {
SamplePortType obj = AOPHandler.getObject();
obj.helloWorld ( );
}
}

您好:看了许多您发的帖子看是震惊啊。您的技术很佩服啊希望能得到您的指导谢谢呵呵
小弟谢了

我是对banq说得啊初来乍到理解