解决Proxy.newProxyInstance创建动态代理导致类型转换错误的问题

来源:互联网 发布:山东知乎 编辑:程序博客网 时间:2024/04/25 02:25

在使用Proxy.newProxyInstance创建动态代理时,有时会导致类型转换错误。

package cn.itcast.demo;


import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;
import javax.sql.DataSource;
import com.mysql.jdbc.Connection;


public class JdbcPool implements DataSource {
private static LinkedList<Connection> list = new LinkedList<Connection>();

static{
try{
InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("driver.properties");
Properties prop = new Properties();
prop.load(in);

String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");

Class.forName(driver);

for(int i=0;i<10;i++){
Connection conn =  (Connection) DriverManager.getConnection(url, username, password);
list.add(conn);
}

}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}

/*
1.写一个子类,覆盖close方法
2、写一个connection的包装类,增强close方法
3、用动态代理,返回一个代理对象出去,拦截close方法的调用,对close进行增强
*/

public Connection getConnection() throws SQLException {
if(list.size()>0){
final Connection conn = list.removeFirst();  
Object obj;
obj = Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(!method.getName().equals("close")){
return method.invoke(conn, args);
}else{
list.add(conn);
return null;
}
}
});
return (Connection)obj;
}else{
throw new RuntimeException();
}
}
...
}

此处将会导致类型转换异常:

java.lang.ClassCastException: $Proxy4 cannot be cast to com.mysql.jdbc.Connection
at cn.itcast.utils.JdbcDyPools.getConnection(JdbcDyPools.java:66)

要想分析其原因,还需要对Proxy.newProxyInstance方法进行了解,其原型为

 java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h) throwsIllegalArgumentException
它创建的代理实现了interfaces接口,由于conn.getClass().getInterfaces()获取到的接口数组是com.mysql.jdbc.Connection继承的接口,所以得到的结果是java.sql.Connection,但是这里需要使用com.mysql.jdbc.Connection;所以导致转换错误


两种解决方法:

1、将代码中的Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), hander);改写为:

Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), new Class[]{com.mysql.jdbc.Connection.class}, hander);

2、创建一个接口继承com.mysql.jdbc.Connection

interface MyConnection extends Connection{

}

这样MyConnection.getClass().getInterfaces()得到是com.mysql.jdbc.Connection,所以下面代码将不会导致转换错误

Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), MyConnection.getClass().getInterfaces(), hander);

原创粉丝点击