|
|
|
使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
作者:stephen
发表时间:2004年12月07日 15:39
回复
原贴网址:
http://www.jdon.com/jivejdon/thread/18095.html
希望能实现一个对象池,但是同时要避免调用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 ( ); } }
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月07日 15:49
|
回复
|
|
|
|
上面的描述有些错别字,论坛好像没有办法对已经发表的帖子做修改,所以在这里加以说明一下:
1.所以原来的代码中,每次使用对象的时候,从工厂里面new一个对象出来,使用完了也不做任何处理。 类似如下代码。
.... SamplePortType obj = SampleFactory.getObject(); obj.helloWorld(); ....
2.另外,由于是示例代码,所以里面涉及多线程同步的问题也“没”做处理。
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月07日 18:49
|
回复
|
|
|
|
http://www.smth.edu.cn/bbsanc.php?path=%2Fgroups%2Fdevelop.faq%2FJavaExpress%2Fjavaprogramming%2FJ2EE%2FAOP%2Fgty5
转贴一篇类似的讨论
☆─────────────────────────────────────☆ 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();
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月07日 18:57
|
回复
|
|
|
|
为什么创建动态代理的时候,对象不从pool中去取呢?另外对象池为什么要用堆栈处理,我觉得用HashSet这样的随机顺序比较好。 public static SamplePortType getObject2() { SamplePortType _orgObject = SamplePool.getInstance().borrowObject(); return (SamplePortType) Proxy.newProxyInstance( _orgObject.getClass().getClassLoader(), _orgObject.getClass().getInterfaces(), new AOPHandler()); }
这样处理的话,都是随机的了。
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月07日 19:06
|
回复
|
|
|
|
或者更加简洁安全的做法: public static SamplePortType getObject2() { SamplePortType _orgObject = new SamplePortType(){ public void helloWorld (){} }; return (SamplePortType) Proxy.newProxyInstance( _orgObject.getClass().getClassLoader(), _orgObject.getClass().getInterfaces(), new AOPHandler()); }
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月07日 19:31
|
回复
|
|
|
|
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 ( ); } }
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月08日 17:56
|
回复
|
|
|
|
之前没详细看 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 ( ); } }
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月13日 14:31
|
回复
|
|
|
|
你的代码我觉得可以,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>
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月13日 17:23
|
回复
|
|
|
|
不清楚楼主的目的是什么,下面我贴出部分我以前写的程序,和你的很类似,通过动态代理产生业务代理层,同时封装事务调用,并且采用配置文件的方式决定对象的产生方式(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; }
}
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月13日 19:50
|
回复
|
|
|
|
非常不错的动态代理程序,同时使用cache提升了性能。 建议 Proxy.newProxyInstance这一句也采取缓存,每次调用,性能也是比较低的。
建议:BeanConfiguration.SINGLETON.equals(config.getMethod())) 这段if else重整一下,可状态模式,通过辅助类映射XML配置。
这段程序可谓是Spring这个大系统的微观,主体思路非常相似。
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月27日 21:56
|
回复
|
|
|
|
是啊,说白了,写这程序的思想就是来自于Spring。 banq说将Proxy.newInstance也缓存起来,其实开始我也是打算如此,只是后来我发现在处理释放池中的内容时会引来一些问题,带来不必要的耦合。至于将BeanConfiguration.SINGLETON.equals(config.getMethod())) 这段改写,倒是一个不错的主意。
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2004年12月28日 12:29
|
回复
|
|
|
|
|
Jdonframework将Proxy.newInstance进行了缓存处理,缺点是引入了J2EE WEB容器。
|
|
|
|
为什么不用静态代理呢?
|
发表: 2005年01月06日 09:45
|
回复
|
|
|
|
我觉得没有必要使用动态代理. 静态的代理也能达到同样的效果.可能我对动态代理的特性掌握不够,请教一下在这里使用动态代理有什么好处?谢谢. 这里是静态代理实现:
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 ( ); } }
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2005年01月18日 22:40
|
回复
|
|
|
|
您好:看了许多您发的帖子看是震惊啊。您的技术很佩服啊希望能得到您的指导谢谢呵呵 小弟谢了
|
|
|
|
Re: 使用Proxy.newProxyInstance包装对象池,免去returnObject方法调用
|
发表: 2005年01月18日 22:44
|
回复
|
|
|
|
|
|
|
|
这个主题共有 18 回复 / 2 页 [
1 2
下一页
]
| |
|
|
|
|