sanshui_yangfei 2019-11-09 21:46 采纳率: 20%
浏览 376
已采纳

java 代理对象 在加入list以后变回了非代理对象,是正常现象么?怎么处理。

本人小白,在学习数据库连接池实现时,为了确保调用者在获取了Connection后,不要直接close。使用动态代理方式创建代理对象,重新处理close函数。在执行中发现,用户在释放了代理对象以后,连接在add进list以后,变回了非代理的ConnectionImpl对象,导致再次取出时,代理作用丢失,请各位帮忙分析一下是怎么回事?

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.LinkedList;

public class DBPool {
    private int maxSize;//最大连接数
    private int initSize;//初始化连接数
    private int cur = 0;//已经使用的连接数
    private LinkedList<Connection> pool = new LinkedList<Connection>();
//初始化连接池
    public DBPool(int initSize, int maxSize) {
        this.maxSize = maxSize;
        this.initSize = initSize;
        initPool(initSize);

    }

    @Override
    public String toString() {
        return "DBPool [pool=" + pool + "]";
    }
//得到正在使用的连接个数
    public int getCur() {
        return cur;
    }
//连接池中连接个数
    public int getPoolSize() {
        return pool.size();
    }
//初始化连接池方法
    public void initPool(int initSize) {
        for (int i = 0; i < initSize; i++) {
            pool.add(createConnection());
        }
    }
//提供给调用者一个连接
    public Connection getPoolConnection() {
        if (pool.size() > 0) {
            cur++;
            return pool.removeFirst();
        } else if (cur >= maxSize) {
            System.out.println("连接已达到最大值");
            return null;
        } else {
            cur++;
            return createConnection();
        }
    }

    public Connection createConnection() {
        //使用工具类获取数据库连接
        Connection con = MysqlUtils.getConnection();
        //创建代理对象,代理con的close方法,如果连接池不满,就放入连接池,如果连接池满,则调用原close方法。
        Connection proxy = (Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(),
                new Class[]{Connection.class}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result = null;
                        //判断是否close方法
                        if ("close".equals(method.getName())) {
                            // 如果连接池里面连接数<initSize,则直接加入pool
                            if (pool.size() < initSize) {
                                cur--;
                                pool.addLast(con);
                            } else {// 如果连接池>initSize,则直接关闭。
                                cur--;
                                result = method.invoke(con, args);
                            }
                        //如果不是close方法,则直接调用原函数
                        } else {
                            result = method.invoke(con, args);
                        }
                        return result;
                    }
                });
        return proxy;
    }
}

测试方法如下:
@Test
public void testPool() throws SQLException {
//初始化连接池,池大小1,最大连接数2
DBPool pool=new DBPool(1, 2);
//获取2个连接
Connection[] conn=new Connection[2];
for(int i=0;i<conn.length;i++) {
conn[i]=pool.getPoolConnection();
}
//释放两个连接,按照代理处理结果,应该是一个放回连接池,一个关闭。
for(int i=0;i<conn.length;i++) {
if(conn[i]!=null) {
conn[i].close();
conn[i]=null;
}
}
//再次获取2个连接
for(int i=0;i<conn.length;i++) {
conn[i]=pool.getPoolConnection();
}
//再次释放2个连接
for(int i=0;i<conn.length;i++) {
if(conn[i]!=null) {
conn[i].close();
conn[i]=null;
}
}

//预期结果应该是当前使用连接cur=0,池中连接数为1.
System.out.println("当前使用的连接数:"+pool.getCur()+",当前连接池中连接数:"+pool.getPoolSize());
}
执行后结果如下:
当前使用的连接数:1,当前连接池中连接数:1

当前结果与预期结果不一致。
经过调试发现:
1、初始化完毕时,链表内容为:
    pool    LinkedList<E>  (id=299) 
        [0] $Proxy4  (id=313)   
2、第一次获取getPoolConnection(),conn数组内容为:
conn    Connection[2]  (id=322) 
    [0] $Proxy4  (id=307)   
    [1] $Proxy4  (id=331)   
3、第一次放回池中,pool链表内容为和conn数组分别为:
    pool    LinkedList<E>  (id=293) 
        [0] ConnectionImpl  (id=316)    
conn    Connection[2]  (id=322) 
    [0] null    
    [1] null    
4、    第二次获取getPoolConnection(),conn数组内容为:
conn    Connection[2]  (id=322) 
    [0] ConnectionImpl  (id=316)    
    [1] $Proxy4  (id=491)   
同时,在调试时也确实在第二次close两个连接时,conn[0].close没有执行代理程序。
不好意思,没有C币,请大家多包涵。
  • 写回答

1条回答 默认 最新

  • 关注

    这是正常的现象,java代理就是这样的

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘