http://blog.csdn.net/lengjinghk/article/details/52170808
在web项目中,Java访问数据库采用的是多用户操作,需要频繁连接数据库,一种方法是来一个请求给一个操作对象,这种方法想法简单,但存在巨大隐患,如果访问量特别的大,数据库连接对象过多,可能导致奔溃。好的方法是,采用数据库连接时统一管理,包括数据库连接对象的个数限制以及使用后回收。
说到管理,根据程序员习惯,拿到连接对象进行完操作后,一般会关闭连接对象,这就会产生一个问题,下一次别的用户再拿到回收后的关闭对象后,由于对象已关闭,再进行其他操作的话,会产生异常。所以我们要修改close()这个函数的功能。
思路:要修改函数功能,基本上是采用覆盖的方法,一种方式是采用装饰模式,即继承加组合,但这种方式有个弊端,如果要实现的接口有很多函数,代码量非常大,所以一般不采用。另一种方式是采用代理模式。下面想详细叙述
代理要用到一个关键的API 类,即Proxy,此外要用到一个接口和接口的一个实例对象。
Proxy.newProxyInstance(loader, interfaces, h);
第一个参数:与被代理对象处于同一空间的类加载器
第二个参数:要实现接口数组
第三个参数:实现功能的句柄对象
下面是一个租房者通过中介租房的例子来演示:
接口
public interface IRenter { public abstract void rent(int n); }
接口实现类
public class Renter implements IRenter{ @Override public void rent(int n) { System.out.println("给你"+n+"间房,请交500元钱"); } }
关键类
public class Client { private static IRenter rent = new Renter(); public static void main(String[] args) { Object obj = Proxy.newProxyInstance(Client.class.getClassLoader(), // new Class[] { IRenter.class }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("我代理的......"); return method.invoke(rent, args); } }); IRenter o = (IRenter) obj; o.rent(3); } }
根据原理。做一个代理工具类:
public class ProxyUtil implements InvocationHandler{
private Object srcObj;
public ProxyUtil(Object srcObj) {
super();
this.srcObj = srcObj;
}
public static Object getProxy(Object srcObj){
Object obj = Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(),
srcObj.getClass().getInterfaces(),
new ProxyUtil(srcObj)
);
return obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(srcObj, args);
}
}
数据库连接池的代码实现:
package me.gacl.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.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.LinkedList; import java.util.Properties; import javax.sql.DataSource; /** * @ClassName: JdbcPool * @Description:编写数据库连接池 * @author: 孤傲苍狼 * @date: 2014-9-30 下午11:07:23 * */ public class JdbcPool implements DataSource{ /** * @Field: listConnections * 使用LinkedList集合来存放数据库链接, * 由于要频繁读写List集合,所以这里使用LinkedList存储数据库连接比较合适 */ private static LinkedList<Connection> listConnections = new LinkedList<Connection>(); static{ //在静态代码块中加载db.properties数据库配置文件 InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties"); Properties prop = new Properties(); try { prop.load(in); String driver = prop.getProperty("driver"); String url = prop.getProperty("url"); String username = prop.getProperty("username"); String password = prop.getProperty("password"); //数据库连接池的初始化连接数大小 int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize")); //加载数据库驱动 Class.forName(driver); for (int i = 0; i < jdbcPoolInitSize; i++) { Connection conn = DriverManager.getConnection(url, username, password); System.out.println("获取到了链接" + conn); //将获取到的数据库连接加入到listConnections集合中,listConnections集合此时就是一个存放了数据库连接的连接池 listConnections.add(conn); } } catch (Exception e) { throw new ExceptionInInitializerError(e); } } @Override public PrintWriter getLogWriter() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { // TODO Auto-generated method stub } @Override public void setLoginTimeout(int seconds) throws SQLException { // TODO Auto-generated method stub } @Override public int getLoginTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { // TODO Auto-generated method stub return false; } /* 获取数据库连接 * @see javax.sql.DataSource#getConnection() */ @Override public Connection getConnection() throws SQLException { //如果数据库连接池中的连接对象的个数大于0 if (listConnections.size()>0) { //从listConnections集合中获取一个数据库连接 final Connection conn = listConnections.removeFirst(); System.out.println("listConnections数据库连接池大小是" + listConnections.size()); //返回Connection对象的代理对象 return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(!method.getName().equals("close")){ return method.invoke(conn, args); }else{ //如果调用的是Connection对象的close方法,就把conn还给数据库连接池 listConnections.add(conn); System.out.println(conn + "被还给listConnections数据库连接池了!!"); System.out.println("listConnections数据库连接池大小为" + listConnections.size()); return null; } } }); }else { throw new RuntimeException("对不起,数据库忙"); } } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } }