spring学习第三天动态代理的具体运用——连接池的原理

25 篇文章 0 订阅

连接池的原理是基于动态代理重写了close方法。

可以使用动态代理实现,也可以使用装饰者模式来实现。

cn.pro.utils.DBUtils

package cn.pro.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

public class DBUtils {
	private static Connection conn ;
	static ResourceBundle rb = ResourceBundle.getBundle("DBconfig");
	
	
	
	static{
		try {
			Class.forName(rb.getString("driver"));
			final String jdbcurl = rb.getString("jdbcurl");
			final String user = rb.getString("user");
			final String passwd =rb.getString("password");
			conn = DriverManager.getConnection(jdbcurl, user, passwd);
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
		
		
	}
	
	public static Connection getConnection(){
		return conn;
		
	}
	
	public static void freeConn(ResultSet rs,Statement st,Connection conn){
			try {
				if(rs!=null){
				rs.close();}
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally
			{
				try {
					if (st != null) {
						st.close();
					}
				} catch (Exception e2) {
					e2.printStackTrace();
				}finally{
					try {
						if (conn != null) {
							conn.close();
						}
					} catch (Exception e3) {
						e3.printStackTrace();
					}
					
				}
			}
			
			
			
		}
		
	}
	
	

/datasource/src/DBconfig.properties

driver=com.mysql.jdbc.Driver
jdbcurl=jdbc:mysql://localhost:3306/springtest
user=root
password=123456

cn.pro.datasource.MyDatasource

package cn.pro.datasource;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import cn.pro.utils.DBUtils;
//自定义连接池  
public class MyDatasource {
	
	//定义一个连接池,用于存放连接 
	//Collections.synchronizedList(new ArrayList<Connection>()); 把ArrayList转化成线程安全的 
	private static List<Connection> pool =  Collections.synchronizedList(new ArrayList<Connection>());
	
	static {
		for(int i=0;i<10;i++){
			Connection conn = DBUtils.getConnection();
			pool.add(conn);
		}
		
		
	}
	
	public static int getPoolsize(){
		return pool.size();
	
		
		
		
		
	}
	
	public static List<Connection> getPool(){
		return pool;
	}
	
	public static Connection getConnection(){
		final Connection conn =  pool.remove(0);
		//用完后需要把连接放入连接池 ,需要对此方法增强 重写connction的close方法
		Connection proxyconn = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				Object RtValue = null;
				//重写close方法,如果是关闭连接 ,则重新键入连接池  
				if("close".equals(method)){
					pool.add(conn);
					
				}else {
					RtValue = method.invoke(conn, args);
					return RtValue;
				}
				return RtValue;
			}
		});
		return proxyconn;
		
	}
}

测试类:

cn.pro.UI.TestConn

package cn.pro.UI;

import java.sql.Connection;
import java.sql.SQLException;

import org.junit.Test;

import cn.pro.datasource.MyDatasource;
import cn.pro.utils.DBUtils;

public class TestConn {
	@Test
	public void test1(){
		Connection conn = DBUtils.getConnection();
		System.out.println(conn);
		
	}
	@Test
	public void test2() throws Exception{
		int size;
		size = MyDatasource.getPoolsize();
		System.out.println(size);
		for (int i=0;i<size;i++){
			System.out.println(MyDatasource.getConnection());
			MyDatasource.getConnection().close();
		}
		
		int size2;
		size2 = MyDatasource.getPoolsize();
		System.out.println(size2);
	}
}

测试test2报错:

Proxy0 cannot be cast to java.sql.Connection

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

因为Connection本身就是一个接口,它的字节码符合第二个参数要求,于是把conn.getClass().getInterfaces();改成new Class[]{Connection.class},问题就解决了

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值