数据库连接池、动态代理

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;
    }
}
 
原文地址:https://www.cnblogs.com/newlangwen/p/8017616.html