设计模式代理模式实现连接池
Posted cynchanpin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式代理模式实现连接池相关的知识,希望对你有一定的参考价值。
1. 连接池
创建Connection的过程是很耗时的,为了保证Conection能够重用。应该将Connection进行池管理。
使用静态工厂方法管理一个唯一的连接:
/** * 用静态工厂方法管理一个唯一的可重用的连接 */ public class ConnUtils { private ConnUtils(){} private static Connection con; //在静态代码块中创建与数据库的连接 static{ try{ Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql:///db_test?characterEncoding=UTf8"; con = DriverManager.getConnection(url,"root","root"); }catch(Exception e){ throw new RuntimeException(e.getMessage(),e); } } //使用静态工厂方法,返回connection实例 public static Connection getCon(){[W1] return con; } }
2. 连接池的实现
为什么要有连接池?
1. 维护多个连接。必需要保证每个线程获取到的是不同的connection对象。
2. 提供一个方法能够回收连接。
下面是最主要的实现:
public class ConnUtils2 { //声明一个容器,放全部声明的连接Connection private static List<Connection> pool = new ArrayList<Connection>(); static{ try{ Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql:///db_test?characterEncoding=UTf8"; for(int i=0;i<3;i++){ //创建三个连接 Connection con = DriverManager.getConnection(url,"root","root"); //将这个三个连接放到pool中去 pool.add(con); } System.err.println("连接:"+pool); }catch(Exception e){ throw new RuntimeException(e.getMessage(),e); } } public static Connection getCon(){ synchronized (pool) { Connection con = pool.remove(0); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.err.println("还有:"+pool.size()); return con; } } //手工还连接 – close public static void back(Connection con){ System.err.println("还连接:"+con); pool.add(con); } }
实际中总是调用close方法,所以为了回收连接。
我们应该重写close方法。对close方法增强。
能够使用下面三种方式进行方法增强:子类,包装,代理。
3. 在代码中调用close时也能够还连接,对close方法进行改动。
动态代理作用:
1. 对某个方法增强。
2. 在不污染源类的情况下。改动原类的行为。
代理类,与被代理类,两个不同的实体。
要求:
全部被代理的类,都必需要实现同一个接口。
本质上是对方法进行改动。但事实上它是通过反射运行的某个方法。
4. 动态代理的核心类
Proxy – 用于创建给定接口的子类。在内存中动态的创建。$Proxy0.此类仅仅使用一次。
InovocationHandler – 运行句柄。
在运行时能够获取被代理类的全部反射。用户的每一次调用都会被这个句柄拦截到。
5. 代理的任务
1. 在内存中创建某个接口的子类。
2. 拦截全部在代理上运行的方法。(除了getClass方法)
6. 用动态代理书写连接池
代理的目标:原生的connection。
代理的目的:改动close方法,让close方法不能够关闭连接。且主动收回连接。
通过动态代理。和线程通讯:
1. 对Connection进行代理。
2. 在获取Connection时。通过同步,假设没有连接时,就让线程进入等待池。
3. 改动close方法。且在还了连接以后唤醒正在等待的线程。
public class ConnUtils3 { //声明连接池维护全部的连接 private static List<Connection> pool = new ArrayList<Connection>(); //静态代码块中创建多个连接 static{ try{ Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql:///db_test?characterEncoding=UTF8"; for(int i=0;i<3;i++){ final Connection con = DriverManager.getConnection(url,"root","root"); //对con对象进行动态代理 Object proxyedCon = Proxy.newProxyInstance( ConnUtils3.class.getClassLoader(), new Class[]{Connection.class}, //声明运行句柄。仅仅对close方法设置拦截 new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { if(method.getName().equals("close")){ System.err.println("想关闭连接,不能关,还连接"); //将proxy再加到pool中,这个proxy就是proxyedCon synchronized (pool) { pool.add((Connection) proxy); pool.notify(); } return null; }else{ System.err.println("放行"+method.getName()); return method.invoke(con, args); // 通过反射运行被代理对象的方法 } } }); //将代理对象加入到池中 pool.add((Connection) proxyedCon); } }catch(Exception e){ throw new RuntimeException(e.getMessage(),e); } } /** * 提供一个静态工厂方法返回一个连接 */ public static Connection getCon(){ synchronized (pool) { if(pool.size()==0){ try { pool.wait(); } catch (InterruptedException e) { e.printStackTrace(); } return getCon(); } Connection con = pool.remove(0);//返回一个代理的connection对象 System.err.println("还有几个:"+pool.size()); return con; } } }
7. 再说连接池的作用
1. 维护多个连接。
在初始化时创建List,将多个连接放到List中去.
2. 能够在close时回收连接
对Connection进行动态代理,
对close方法进行拦截。
Author:顾故
Sign:别输给以前的自己
以上是关于设计模式代理模式实现连接池的主要内容,如果未能解决你的问题,请参考以下文章