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

在使用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) throws IllegalArgumentException
它创建的代理实现了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);

`Proxy.newProxyInstance` 是 Java 中的一个方法,用于创建一个动态代理对象。它接受三个参数:一个加载器,一个接口数组和一个 `InvocationHandler` 对象。动态代理对象可以在运行时动态地创建一个实现指定接口的代理,并将方法调用委托给 `InvocationHandler` 来处理。 使用 `Proxy.newProxyInstance` 可以实现一些横切关注点(cross-cutting concerns)的功能,比如日志记录、性能监控、事务管理等。通过动态代理,可以在不修改原始代码的情况下,为其增加额外的行为。 以下是一个简单的示例代码,演示如何使用 `Proxy.newProxyInstance` 创建一个动态代理对象: ```java public interface Foo { void bar(); } public class RealFoo implements Foo { @Override public void bar() { System.out.println("RealFoo: executing bar()"); } } public class LoggingHandler implements InvocationHandler { private final Object target; public LoggingHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = method.invoke(target, args); System.out.println("After method: " + method.getName()); return result; } } public class Main { public static void main(String[] args) { Foo realFoo = new RealFoo(); InvocationHandler handler = new LoggingHandler(realFoo); Foo proxy = (Foo) Proxy.newProxyInstance( Foo.class.getClassLoader(), new Class[]{Foo.class}, handler); proxy.bar(); // 通过代理对象调用方法 } } ``` 运行上述代码,将会在控制台输出以下内容: ``` Before method: bar RealFoo: executing bar() After method: bar ``` 这说明 `LoggingHandler` 在方法调用前后添加了额外的日志输出行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值