数据库连接池的代理设计模式

    /*动态代理, 技术入口: java.lang.reflect包中,
       Object proxiedObj = Proxy.newProxyInstance(...)
     */

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

//数据库连接池---v3---用户直接调用con.close()就可以实现还回池中---采用动态代理模式增强conn
public class Conn4Utils {
    //创建一个池
    private static List<Connection> pool = new ArrayList<Connection>();
    private static final int NUM=3; 
    
    static{
        try {
            //读取资源文件 properties 
            Properties p = new Properties();
            //当资源文件放在classpath下 ----用类加载器读
            p.load(Conn4Utils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
            
            String driver = p.getProperty("driver");
            String url = p.getProperty("url");
            String user = p.getProperty("username");
            String pwd = p.getProperty("password");
            
            for(int i=0;i<NUM; i++){
                final Connection conn = DriverManager.getConnection(url, user, pwd);//原型对象
                //利用动态代理模式,把conn改成它的代理后的对象conn2放入池中,同时在代理拦截中把close()方法拦截并做成把它还回池中的动作
                Object proxiedObj = Proxy.newProxyInstance(
                        Conn4Utils.class.getClassLoader(), 
                        //conn.getClass().getInterfaces(), //坑:不能替代下一行,因为mysql中使用了自己的类加载器
                        new Class[]{Connection.class},
                        new InvocationHandler() {//回调函数,通过代理后的对象执行的所有方法(接口中有的)都会自动进入这个方法来实现"所调方法的功能"
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args)
                                    throws Throwable {//proxy即是proxiedObj
                                //把close方法拦截并更改成把“代理后的对象”放回池中的动作
                                if("close".equals( method.getName()) ){
                                    pool.add( (Connection)proxy );
                                    System.out.println("往池中还回来一个连接。。。");
                                    return null; //跳过下面的放行,这样原有的close()功能就没了
                                }
                                
                                return method.invoke(conn, args); //放行
                            }
                        });
                Connection conn2 = (Connection) proxiedObj;
                pool.add(conn2);
                //pool.add((Connection) proxiedObj); //代替上面两行
            }
            
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        
    }
    
    public static synchronized Connection getConn(){
        if(pool.size()<=0){
            System.out.println("池中已经没有了,请稍候再连");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return getConn();
        }
        System.out.println("从池中拿走一个...");
        return pool.remove(0);
    }

}

猜你喜欢

转载自blog.csdn.net/qq_35307947/article/details/82795094
今日推荐