标签:
要求:在不修改源码的情况下,对已有的功能进行增强
抽象接口:保证包含增强功能的对象和原有功能的对象,对外提供相同的方法
目标对象:封装了原有功能
代理对象:封装了增强功能和原有功能(通过持有一个目标对象的引用实现)
问题:代码不够灵活,产生大量冗余工作
动态代理的实现API:
Proxy :
帮助程员产生代理对象,提供产生代理类和代理对象的静态方法
InvocationHandler :
句柄接口,拦截到,所有代理对象调用的方法(所有代理对象调用的方法,都可以被
InvocationHandler拦截到)
模拟实现数据库连接池
数据库的操作:考虑性能问题
频繁的连接和断开数据,本身很消耗资源(操作数据的性能)
---对数据库连接对象,进行池管理(由池中获得资源,用完之后将资源再次放入)
连接池的具体实现:
1 创建一个集合对象,封装n个Connection对象
2 定义获得连接
3 和归还连接的功能
实现代码:
1 public class DBPoolUtils { 2 private static String driver; 3 private static String url; 4 private static String username; 5 private static String password; 6 private static int maxconn;//线程池最大的连接数 7 8 //定义一个集合表示线程池 9 static List<Connection> list=new ArrayList<Connection>(); 10 //类加载的时候就初始化,创建好连接对象 11 static{ 12 Properties properties=new Properties(); 13 try { 14 //读取配置文件信息 15 properties.load(DBPoolUtils.class.getResourceAsStream("mysql.properties")); 16 driver=properties.getProperty("driver"); 17 url=properties.getProperty("url"); 18 username=properties.getProperty("username"); 19 password=properties.getProperty("password"); 20 maxconn=Integer.parseInt(properties.getProperty("maxconn")); 21 Class.forName(driver); 22 /* 23 * 创建连接对象 24 * 因为当用户关闭的时候要把线程连接对象还到线程池中, 25 * 所有拿到的对象与还回来的对象都应该是代理对象。 26 * 对close()方法进行拦截,把原来断开连接改成将线程连接对象还到连接池 27 */ 28 for (int i = 0; i < maxconn; i++) { 29 final Connection conn=DriverManager.getConnection(url, username, password); 30 //创建代理对象 31 Object connProxy=Proxy.newProxyInstance( 32 DBPoolUtils.class.getClassLoader(),//自定义类的类加载器 33 new Class<?>[]{Connection.class},//实现的接口的class文件数组 34 new InvocationHandler() {//匿名内部类实现InvocationHandler 35 36 @Override 37 public Object invoke( 38 Object proxy,//代理对象 39 Method method,//代理对象实现接口中调用的方法 40 Object[] args//代理对象实现接口中调用的方法中的参数 41 )throws Throwable { 42 //拦截close()方法,将原来的断开连接改为还回连接池,即:将当前的代理对象加到线程池中 43 String methodName=method.getName(); 44 if ("close".equals(methodName)) { 45 list.add((Connection) proxy); 46 //唤醒等待的线程 47 synchronized (list) { 48 list.notifyAll(); 49 } 50 } 51 //放行:调用原来的对象方法 52 Object obj=method.invoke(conn, args); 53 return obj; 54 } 55 }); 56 //将创建好的代理线程对象加线程池 57 list.add((Connection) connProxy); 58 } 59 } catch (IOException e) { 60 e.printStackTrace(); 61 } catch (ClassNotFoundException e) { 62 e.printStackTrace(); 63 } catch (SQLException e) { 64 e.printStackTrace(); 65 } 66 } 67 /** 68 * 对外提供一个连接对象 69 * @return 70 */ 71 public static Connection getConnection(){ 72 //当线程池中没有连接对象的时候,让线程等待,而不报异常,等待其他线程返回时再唤醒 73 synchronized (list) { 74 if (list.size()==0) { 75 try { 76 list.wait(); 77 } catch (InterruptedException e) { 78 e.printStackTrace(); 79 } 80 } 81 } 82 //每次从线程池中取出第一个线程 83 Connection conn=list.remove(0); 84 System.out.println("剩余:"+list.size()); 85 return conn; 86 } 87 }
总结代理模式 并根据数据库连接池原理来模拟实现自己的数据库连接池工具类
标签:
原文地址:http://www.cnblogs.com/bingzhikun/p/4799939.html