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

04-12-07 stephen
希望能实现一个对象池,但是同时要避免调用returnObject。

因为如果可以避免调用returnObject,那么就原来的代码就可以不做修改就能使用对象池优化功能了。

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

先声明一点,准备保存到池里面的对象是不用在两次调用之间保存状态的。

所以下面的示例代码中,每次调用一个方法的时候,都从池里面找一个对象,用完之后,立即归还。

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

类似如下代码。

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

<p>

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

代码虽然写了出来,就这个示例程序来说,也能跑了,

但是对其中的实现方法存在一些疑问。

主要的疑问是,示例代码中,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 ( );
  }
}

<p>

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

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

类似如下代码。

....
SamplePortType obj = SampleFactory.getObject();
obj.helloWorld();
....
<p>

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

stephen
2004-12-07 18:49

转贴一篇类似的讨论

☆─────────────────────────────────────☆
   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();
<p>

ljshan
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());

}

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

ljshan
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());

}

stephen
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 ( );
  }
}

stephen
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);

<p>

多谢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 ( );
  }
}

<p>

banq
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>
<p>

凤舞凰扬
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;

}

}

banq
2004-12-13 19:50
非常不错的动态代理程序,同时使用Cache提升了性能。

建议 Proxy.newProxyInstance这一句也采取缓存,每次调用,性能也是比较低的。

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

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

凤舞凰扬
2004-12-27 21:56
是啊,说白了,写这程序的思想就是来自于spring。

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

banq
2004-12-28 12:29
Jdonframework将Proxy.newInstance进行了缓存处理,缺点是引入了J2EE WEB容器。

fanf
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 ( );

}

}

newPlay
2005-01-18 22:40
您好:看了许多您发的帖子看是震惊啊。您的技术很佩服啊希望能得到您的指导谢谢呵呵

小弟谢了

newPlay
2005-01-18 22:44
我是对banq说得啊初来乍到理解

猜你喜欢
2Go 1 2 下一页