在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);
}
}
数据库连接池的代码实现:
public class ConnsUtil {
private static List<Connection>pool = new ArrayList<Connection>();
private static int num = 3;
static{
Properties p = new Properties();
try {
p.load(ConnsUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"));
String driver = p.getProperty("driver");
String url = p.getProperty("url");
String user = p.getProperty("username");
String password = p.getProperty("password");
Class.forName(driver);
for(int i=0;i<num;i++){
final Connection conn = DriverManager.getConnection(url, user, password);
Connection con = (Connection)Proxy.newProxyInstance(
ConnsUtil.class.getClassLoader(),
new Class[]{Connection.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(method.getName().equalsIgnoreCase("close")){
pool.add((Connection)proxy);
return null;
}
return method.invoke(conn, args);
}
}
);
pool.add(con);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static synchronized Connection getConnection(){
if(pool.size()<=0){
try {
Thread.sleep(100);
return getConnection();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return pool.remove(0);
}
}