【Java】使用动态代理与包装模式实现连接池

一:动态代理模式

创建一个ConnPoolUtil2类:

public class ConnPoolUtil2 implements DataSource{
	// 创建一个连接池
	public LinkedList<Connection> pool = new LinkedList<>();
	
	public ConnPoolUtil2(){
		try {
			Class.forName("com.mysql.jdbc.Driver");
			String dbUrl = "jdbc:mysql://localhost:3306/test";
			String dbUserName = "root";
			String dbPassWord = "root";
			
			int connSize = 3;
			// 创建三个连接,并存进连接池pool
			for (int i = 0; i < connSize; i++) {
				final Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassWord);
				// 对conn进行代理
				Proxy proxyObj = (Proxy) Proxy.newProxyInstance(ConnPoolUtil2.class.getClassLoader(), 
						new Class[]{Connection.class}, 
						new InvocationHandler() {			
							@Override
							public Object invoke(Object proxy, Method method, Object[] args)
									throws Throwable {
								// 如果是close方法,则不让执行,不关闭连接,而是将连接放回连接池
								if (method.getName().equals("close")) {
									synchronized (pool) {
										pool.addLast((Connection) proxy);  // proxy是被代理对象
										pool.notify();// 通知让知道连接池中有可用连接
									}
									return null;  // 返回空,意味着如果是close方法则不会调用被代理类的方法
								}
								return method.invoke(conn, args);
							}
						});
				// 将代理对象添加到连接池中
				pool.add((Connection) proxyObj);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	@Override
	public Connection getConnection() throws SQLException {
		synchronized (pool) {
			if (pool.size()==0) {
				try {
					pool.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				return getConnection();
			}	
			Connection conn = pool.removeFirst();
			System.out.println("连接池还有"+pool.size()+"个连接");
			return conn;
		}
	}
	// 这里省略其他未实现的方法


二:包装(装饰器)模式

创建一个ConnPoolUtil3类:

public class ConnPoolUtil3 implements DataSource{
	// 创建一个连接池
	public LinkedList<Connection> pool = new LinkedList<>();
	
	public ConnPoolUtil3(){
		try {
			Class.forName("com.mysql.jdbc.Driver");
			String dbUrl = "jdbc:mysql://localhost:3306/test";
			String dbUserName = "root";
			String dbPassWord = "root";
			
			int connSize = 3;
			for (int i = 0; i < connSize; i++) {
				Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassWord);
				MyConnection myConn = new MyConnection(conn);  // 包装类
				pool.add(myConn);
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public Connection getConnection() throws SQLException {
		synchronized (pool) {
			if (pool.size()==0) {
				try {
					pool.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				return getConnection();
			}	
			Connection conn = pool.removeFirst();
			System.out.println("连接池还有"+pool.size()+"个连接");
			return conn;
		}
	}
	
	// 包装类(对Connection进行包装,1.先成为Connection的子类;2.声明一个Connection成员)
	class MyConnection implements Connection{
		private Connection conn;
		public MyConnection(Connection conn){
			this.conn = conn;
		}
		/**
		 * 包装原Close方法
		 */
		@Override
		public void close() throws SQLException {
			synchronized (pool) {
				System.out.println("不能关闭连接,要还连接"+conn);
				pool.add(conn);
				pool.notify();
			}
		}
	// 这里省略其他未实现的方法


这里写一个测试连接池的类:ThreadTestPool

public class ThreadTestPool {
	public static void main(String[] args) throws Exception {
		for(int i = 0; i< 100; i++){
			new MyThread().start();
		}
	}
}

class MyThread extends Thread{
	@Override
	public void run() {
		Connection conn = null;
		try{
			ConnPoolUtil2 connPoolUtil2 = new ConnPoolUtil2();
			conn = connPoolUtil2.getConnection();
			System.out.println(this.getName()+","+conn);
			conn.setAutoCommit(false);  // 设置事务的开始
			String sql = "insert into t_book values(null,'"+this.getName()+"','1')";
			Statement st = conn.createStatement();
			st.execute(sql);
			conn.commit();
			System.out.println(this.getName()+"子线程执行完成。。。。。");
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				conn.setAutoCommit(true);
				conn.close();  // 尝试关闭连接
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}


1.代理和包装都是对方法进行增强;代理:根据给定的接口,在内存中创建这个接口的子类($Proxy); 包装:不用接口,是声明一个类,再继承被包装类,同时拥有一个被包装类的成员。

2.代理基本形式:

Object proxyedObj =
       Proxy.newProxyInstance(ClassLoader,
                            New class[]{  // 被代理的类的接口数组.class},
                            New InvocationHandler(){  // 执行句柄
                               Public Object invode(Object 代理,Method 方法反射,object[] args){
                                    Reutrn method.invode(被代理类,args);
                                }
                            }

3.包装基本形式:

A extends B{  // A包装B
    Privet B b;   
}

4.一般情况下,如果有官方提供的包装类适配器,就优先使用包装类,比如GenericServlet,HttpServletRequest,它的包装类是HttpServletRequestWraper(可以包装getParameter方法,解决get方式提交乱码问题);如果官方没有提供的包装类适配器,可以使用动态代理。




你可能感兴趣的:(【Java】使用动态代理与包装模式实现连接池)