介绍
Spring框架是目前开发中使用最广泛框架,spring的核心功能一个是ioc一个是aop.。Aop的核心功能就是使用java的动态代理,在许多框架中也使用了动态代理,目前在看mybatis源码,数据库连接池中,关闭connection连接中,是将connection放回了连接池,而不是调用了close()方法,这块就使用了动态代理的方式,我先介绍下动态代理的实现方式,后面介绍mybatis连接池在这块的使用。
java的动态代理主要涉及两个类一个接口类InvocationHandler ,一个代理类java.lang.reflect.Proxy
jdk源码
package java.lang.reflect;
public interface InvocationHandler {
/*proxy:实际的对象
*method:代理嗲用的方法
args: 方法参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
动态代理实现
- 定义接口类
public interface HelloInterface {
String sayHello(String msg);
}
- 定义实现类
public class HelloImpl implements HelloInterface {
@Override
public String sayHello(String msg) {
System.out.println("他说:"+msg);
return msg;
}
}
3 定义handler类
public class HeloProxy implements InvocationHandler {
private static final Class<?>[] IFACES = new Class<?>[] { HelloInterface.class };
private final HelloInterface helloInterface; // 被代理的类
private final HelloInterface realInterface; // 实际的原始类
public HeloProxy(HelloInterface helloInterface) {
realInterface = helloInterface;
this.helloInterface = (HelloInterface) Proxy.newProxyInstance(HelloInterface.class.getClassLoader(),IFACES,this);
//生成代理类
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当通过helloInterface调用方法sayHello 是走的这里
String name = method.getName();
System.out.println("当前调用方法"+name);
return method.invoke(realInterface,args);
}
public HelloInterface getHelloInterface() {
return helloInterface;
}
}
4 main 方法
HelloInterface helloInterface = new HelloImpl();
HeloProxy heloProxy = new HeloProxy(helloInterface);
String string = heloProxy.getHelloInterface().sayHello("动态代理");
System.out.println(string);
输出结果:
当前调用方法sayHello
他说:动态代理
动态代理
Proxy类我们主要调用方法newProxyInstance方法,调用该方法生成代理类
// ClassLoader loader 被代理类的加载器
// interfaces 被代理类的interface
//InvocationHandler 实现该接口的方法类
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
mybaitis 应用
在mybatis中,为了减少与数据库的连接次数,减少消耗的性能,我们一般都使用连接池,再使用完connnection后不是关闭连接而是放入连接池中。从连接池取到connection就是被代理过的连接。
从连接池中获取连接的代码
public class PooledDataSource implements DataSource
@Override
public Connection getConnection() throws SQLException {
return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
// 从这个可知我们从连接池中获取到的连接是被代理过的connection
}
实现InvocationHandler 的类
class PooledConnection implements InvocationHandler
//构造器
public PooledConnection(Connection connection, PooledDataSource dataSource) {
this.hashCode = connection.hashCode();
this.realConnection = connection;
this.dataSource = dataSource;
this.createdTimestamp = System.currentTimeMillis();
this.lastUsedTimestamp = System.currentTimeMillis();
this.valid = true;
this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
// 这个proxyConnection 就是上面的.getProxyConnection();
}
// invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
//在这里我们得知,当connection调用close方法时,并没有真正调用close()方法,而是放入到了连接池中
dataSource.pushConnection(this);
return null;
}
try {
if (!Object.class.equals(method.getDeclaringClass())) {
// issue #579 toString() should never fail
// throw an SQLException instead of a Runtime
checkConnection();
}
return method.invoke(realConnection, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}