• 【Java EE 学习 15】【自定义数据库连接池之动态代理的使用】


    一、动态代理的作用

      使用动态代理可以拦截一个对象某个方法的执行,并执行自定义的方法,其本质是反射

      优点:灵活

      缺点:由于其本质是反射,所以执行速度相对要慢一些

    二、数据库连接池设计思想

      1.为什么要使用数据库连接池:创建Connection对象的过程是非常耗时的,为了保证Connection可以重用,应该对Connection进行管理。

      2.设计要求:

        (1)连接池能够实现维护多个连接,必须要保证每一个线程获取到的是不同的Connection对象。

        (2)提供一个方法能够回收连接。

      3.最基本的实现

    package day15_2;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.ArrayList;
    
    /**
     * 使用最基本的方式创建数据库连接池
     * @author kdyzm
     *
     */
    public class JDBCPool1 {
        private static ArrayList<Connection>pool=new ArrayList<Connection>();
        static
        {
            try {
                Class.forName("com.mysql.jdbc.Driver");
                String url="jdbc:mysq://localhost:3306?useUnicode=true&characterEncoding=utf-8";
                for(int i=0;i<5;i++)
                {
                    Connection conn=DriverManager.getConnection(url, "root", "5a6f38");
                    pool.add(conn);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        public Connection getConn()
        {
            synchronized (pool) {
                Connection conn=pool.remove(0);
                System.out.println("还有 "+pool.size()+"个连接");
                return conn;
            }
        }
        
        public static void back(Connection conn)
        {
            System.out.println("还连接:"+conn);
            pool.add(conn);
        }
    }

      4.程序员写代码总是习惯性的调用close方法,如果实际调用了close方法,则该连接将会被释放,再也回收不回来了,所以应当使用一种方法拦截close方法的执行,并且替换成自定义的动作。使用代理可以完成这个任务。

      代码示例:

    import java.io.File;
    import java.io.FileInputStream;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.net.URL;
    import java.net.URLDecoder;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.util.LinkedList;
    import java.util.Properties;
    public class ConnUtils {
        private static LinkedList<Connection> pool = new LinkedList<Connection>();
        static{
            try {
                //声明资源器类 - 
                Properties prop = new Properties();
                //获取这个文件的路径
                URL url = ConnUtils.class.getClassLoader().getResource("jdbc.properties");
                String path = url.getPath();
                //为了防止有中文或是空格
                path = URLDecoder.decode(path,"UTf-8");
                File file = new File(path);
                //加载jdbc.properties这个文件
                prop.load(new FileInputStream(file));
                //获取信息
                String driver = prop.getProperty("driver");
                Class.forName(driver);
                String jdbcurl = prop.getProperty("url");
                String nm = prop.getProperty("name");
                String pwd = prop.getProperty("pwd");
                //创建三个原生的连接,都将它们代理
                String poolSize = prop.getProperty("poolSize");
                int size = Integer.parseInt(poolSize);
                for(int i=0;i<size;i++){
                    final Connection con = DriverManager.getConnection(jdbcurl,nm,pwd);
                    //对con进行动态代理
                    Object proxyedObj = 
                            Proxy.newProxyInstance(ConnUtils.class.getClassLoader(),
                                        new Class[]{Connection.class},
                                        new InvocationHandler() {
                                            public Object invoke(Object proxy, Method method, Object[] args)
                                                    throws Throwable {
                                                //是否是close方法
                                                if(method.getName().equals("close")){
                                                    synchronized (pool) {
                                                        pool.addLast((Connection) proxy);
                                                        pool.notify();
                                                    }
                                                    return null;//如果调用的是close则不会调用被代理类的方法。
                                                }
                                                return method.invoke(con, args);
                                            }
                                        });
                    //将代理对象放到pool中
                    pool.add((Connection) proxyedObj);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        public static Connection getConn(){
            synchronized (pool) {
                if(pool.size()==0){  //如果连接池中没有连接则进入等待池中等待
                    try {
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return getConn();
                }else{          //如果连接池中有连接则将连接分配出去。
                    Connection con = pool.removeFirst();
                    System.err.println("还有几个:"+pool.size());
                    return con;
                }
            }
        }
    }

      5.动态代理的核心类。

      (1)Proxy类:提供用于创建动态代理类和实例的动态方法,它还是由这些方法创建的所有动态代理类的超类。

      (2)InvocationHandler接口:是代理实例的调用处理程序实现的接口。

      6.代理的任务

      (1)在内存中创建某个接口的子类。

      (2)拦截所有在代理上执行的方法。

    三、联系人管理小练习。

      源代码:https://github.com/kdyzm/day15

      

  • 相关阅读:
    4.2 面向对象分析(二) CRC方法标识概念类
    4.1 面向对象分析(二) 标识概念类和对象
    3.4 面向对象分析(一)面向对象设计(初步)
    3.3 面向对象分析(一)分析模型法
    3.2 面向对象分析(一)名词法
    3.1 面向对象分析与设计概览
    2.7 UML状态图
    2.6 通信图
    2.5 UML顺序图
    2.4 UML类图
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4678145.html
Copyright © 2020-2023  润新知