【转】解决$Proxy0 cannot be cast to java.sql.Connection异常

在模拟写数据库连接池的时候使用动态代理设计模式,然后出现了如题的错误,很是郁闷,最后经百度找到了如下的解决方法:
解决:
可以将 getConnection() 方法内的 conn.getClass().getInterfaces() 换成 new Class[]{Connection.class} 即可。

在使用动态代理增强Connection连接对象的close方法时,我碰到了如题所示的异常。通过搜索我发现这个异常出现的原因在于我使用的mysql数据库驱动的问题,由于数据库驱动不同,Connection.class.getInterfaces()返回的结果也不同,它返回的是一个Class[]数组,然而此数组的第一个元素必须是Connection才能把创建的代理类转为Connection对象,否则就会报错。

Connection.getInterfaces() 与 new Class[]{Connection.class} 2个使用方式的原因:

原来Connection.getInterfaces() 与数据库驱动有关,数据库驱动不同 Connection.getInterfaces() 的结果也就不同;Connection.getInterfaces() 返回的是 Class[] 数组,此数组的第一个元素必须是Connection才能把创建的代理类转为Connection对象,否则就会报:java.lang.ClassCastException 了

 所以这里我们可以采取一个替代方式替换Connection.class.getInterfaces(),即new Class[] { Connection.class },这样无论数据库驱动是什么版本的驱动,都能保证这个类型转换不出错。
代码(部分省略):

public class MyPool implements DataSource{
    //ArrayList--底层是数组,方便查找,不方便增删
    //LinkedList--底层是链表,方便增删,不方便查找
    private static List<Connection> pool = new LinkedList<Connection>();

    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");
            for(int i=0;i<5;i++){
                Connection conn = DriverManager.getConnection("jdbc:mysql:///day11","root","123");
                pool.add(conn);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }

    public Connection getConnection() throws SQLException {
        if(pool.size()==0){
            for(int i=0;i<3;i++){
                Connection conn = DriverManager.getConnection("jdbc:mysql:///day11","root","123");
                pool.add(conn);
            }
        }
        final Connection conn = pool.remove(0);

        //在返回connection对象之前,利用动态代理改造Connection 的 close()方法
            //返回代理对象
        Connection proxy = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), new Class[]{Connection.class}, 
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        if("close".equals(method.getName())){
                            retConn(conn);
                            return null;
                        }else{
                            return method.invoke(conn, args);
                        }
                    }
                });
        System.out.println("获取了一个连接,池里还剩"+pool.size()+"个");
        return proxy;
    }
    //还回连接
    private void retConn(Connection conn) {
        try {
            if(conn!=null && !conn.isClosed()){
                System.out.println("还了一个连接,池里还剩"+pool.size()+"个");
                pool.add(conn);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
posted @ 2016-02-27 11:18  时光.漫步  阅读(648)  评论(0编辑  收藏  举报