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代理就是这样的

sanshui_yangfei
sanshui_yangfei 那请问如何处理这种,回收以后再取出,希望仍然能够具有代理特征的需求?
3 个月之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问

相似问题

1
java层面List<Integer>与List<Double>是两个不同的类型
1
Java List<List<Integer>> 取有交集的元素的集合
1
【JAVA】怎么把list中对象某两个属相相同的拿出来,用stream
1
Java list分页的问题求大神告知 本人新手
2
java8 如何对list操作 根据某一个字段进行判断去重对另一个字段进行累加 最终返回list?
5
Java中怎么让list里的数据根据类别打印出来
1
创建List对象,老是报错The left-hand side of an assignment must be a variable?
2
Java:如何向方法中传递list,而不改变list的属性?
4
request的getAttribute方法无法解析list中的对象
5
JAVA list集合内以Map格式 强制转换map怎么做?
1
restTemplate能否传递list集合?
3
导入Java项目,xml文件中出现<#List></#List>一直报这个错误 The content of elements must consist of well-formed character data or markup
1
如何使用Java8Lambda表达式对两个List<Object>中的多个元素进行对比筛选
3
spring整合mybatis时,加入声明式事务控制,必须使用子类的代理方式,否则报错
2
java的List集合里面放了Map,List<Map<String,Object>>,如何判定人名相同,就组合成一个对象?
2
将map对象转换为list时报错'list' object is not callable?
3
怎么把sql查询到的数据用java封装成对象放到list里?
2
java 集合什么情况需要用到迭代器
2
Java利用线程池周期性的执行100个线程同时去ping
0
java8stream 求和操作 超出long类型最大值