对自定义数据库连接池中的close方法加强,使其在调用的时候并不是关闭连接,而是将连接添加回连接池(装饰者模式)

如果你不太清楚装饰者模式,请看我的另一篇简短的文章:https://blog.csdn.net/yjzq2280044399/article/details/85340214
如果你对数据库连接池不太清楚:请看我的另一篇文章:
https://blog.csdn.net/yjzq2280044399/article/details/85690607

条件:
1.装饰者和被装饰者实现同一个接口或者继承同一个类
2.装饰者中要有被装饰者的引用
3.对需要增强的方法进行加强
4.对不需要加强的方法调用原来方法

我们要对connection进行装饰,首先我们得明白connection是怎么来的。不然我们根本不知道装饰的是哪个类中的方法。

public class DriverManager {
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();

private static Connection getConnection(
	for(DriverInfo aDriver : registeredDrivers) {
	            // If the caller does not have permission to load the driver then
	            // skip it.
	            if(isDriverAllowed(aDriver.driver, callerCL)) {
	                try {
	                    println("    trying " + aDriver.driver.getClass().getName());
	                    Connection con = aDriver.driver.connect(url, info);
	                    if (con != null) {
	                        // Success!
	                        println("getConnection returning " + aDriver.driver.getClass().getName());
	                        return (con);
	                    }
	                } catch (SQLException ex) {
	                    if (reason == null) {
	                        reason = ex;
	                    }
	                }
	
	            } else {
	                println("    skipping: " + aDriver.getClass().getName());
	            }
	
	        }
	    }
	 }   

第一步:通过上面的代码我们可以知道:DriverManager调用getconnection方法,conn 是通过aDriver.driver.connect(url, info);得到的,而aDriverregisteredDrivers最终集合中的一个元素。所以我们要清楚registeredDrivers最终集合中的元素怎么来的。

该方法需要registeredDrivers最终集合进行遍历,所以在之前registeredDrivers最终集合肯定已经执行过添加元素的方法。所以我们要找到这个方法。
我通过检索源代码文件找到了FabricMySQLDriver这个类。

package com.mysql.fabric.jdbc;
public class FabricMySQLDriver extends NonRegisteringDriver implements Driver {
  static {
        try {
            DriverManager.registerDriver(new FabricMySQLDriver());
        } catch (SQLException ex) {
            throw new RuntimeException("Can't register driver", ex);
        }
    }
}

第二步:结果发现它的静态代码块调用了
DriverManager.registerDriver,然后我又找到了这里。

package java.sql;
public class DriverManager {
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();`

 public static synchronized void registerDriver(java.sql.Driver driver)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println("registerDriver: " + driver);
    }
	
}

发现这个方法就是添加元素的方法。FabricMySQLDriver的静态代码块中调用了类DriverManager中的registeredDrivers方法。
registeredDrivers的定义代码:private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();
核心的代码就是:
DriverManager.registerDriver(new FabricMySQLDriver());
public static synchronized void registerDriver(java.sql.Driver driver)
registeredDrivers.addIfAbsent(new DriverInfo(driver));

把上面的代码合并理解:
java.sql.Driver driver = new FabricMySQLDriver();
DriverInfo dri = new DriverInfo(driver);
我们先把这一步拆开,即:
FabricMySQLDriver fms = new FabricMySQLDriver();
java.sql.Driver driver = fms;
即:
DriverManager.registerDriver(fms);
public static synchronized void registerDriver(fms)
registeredDrivers.addIfAbsent(new DriverInfo(fms));

第三步:
registeredDrivers方法又调用了一个addIfAbsent来完成这个操作,我们不需要再往下看了,因为这个时候我们已经搞清楚了,registeredDrivers集合中的元素就是DriverInfo类型的对象。可能有的人会说那照你这样说一开始我们就通过:
for(DriverInfo aDriver : registeredDrivers)知道了registeredDrivers集合中的元素就是DriverInfo类型的对象啊,还绕了半天,有什么意义呢?OK,那我们再来看看DriverInfo这个类,再看这个类之前,我们先回顾一下conn怎么来的:
Connection con = aDriver.driver.connect(url, info);
可以理解为:DriverInfo.driver.connect(url, info);

package java.sql;
class DriverInfo {

    final Driver driver;
    DriverInfo(Driver driver) {
        this.driver = driver;
    }
    public boolean equals(Object other) {
        return (other instanceof DriverInfo)
                && this.driver == ((DriverInfo) other).driver;
    }
    public int hashCode() {
        return driver.hashCode();
    }
    public String toString() {
        return ("driver[className="  + driver + "]");
    }
}

第四步:如果我们抛开前两步直接看这里,那么就有一个问题,driver是谁,因为conn是通过这个driver调用connect方法得到的
通过这里面的代码我们可以知道,其实源码可以这样理解:
final Driver driver; DriverInfo(fms) { this.driver =fms; }
所以这个时候的diver就知道是谁了吧。就是fmsFabricMySQLDriver
那么最后了,conn怎么来的呢,就是fms.connect
所以只需要去FabricMySQLDriver中查找connect方法即可。

 public Connection connect(String url, Properties info) throws SQLException {
        Properties parsedProps = parseFabricURL(url, info);

        if (parsedProps == null) {
            return null;
        }

        parsedProps.setProperty(FABRIC_PROTOCOL_PROPERTY_KEY, "http");
        if (com.mysql.jdbc.Util.isJdbc4()) {
            try {
                Constructor<?> jdbc4proxy = Class.forName("com.mysql.fabric.jdbc.JDBC4FabricMySQLConnectionProxy")
                        .getConstructor(new Class[] { Properties.class });
                return (Connection) com.mysql.jdbc.Util.handleNewInstance(jdbc4proxy, new Object[] { parsedProps }, null);
            } catch (Exception e) {
                throw (SQLException) new SQLException(e.getMessage()).initCause(e);
            }
        }

        return new FabricMySQLConnectionProxy(parsedProps);
    }

即DriverManager中的Connection con = new FabricMySQLConnectionProxy(parsedProps)
父类引用指向子类对象。

接口:connection
mysql对齐的实现类:connection
所以要先看实现类中的原close方法。
装饰类:ConnectionWarp
被装饰者:FabricMySQLConnectionProxy
查看源代码发现该类中确实有close方法。

下面是装饰类的内容:

public class ConnectionWarp implements Connection {
	
	private Connection conn;
	private LinkedList<Connection> list;

	public ConnectionWarp(Connection conn){
		this.conn=conn;
	}
	
	public ConnectionWarp(Connection conn,LinkedList<Connection> list){
		this.conn=conn;
		this.list=list;
	}
	
	@Override
	//不需要加强的方法 调用原来的
	public Statement createStatement() throws SQLException {
		// TODO Auto-generated method stub
		return conn.createStatement();
	}
	
	@Override
	//不需要加强的方法 调用原来的
	public PreparedStatement prepareStatement(String sql) throws SQLException {
		// TODO Auto-generated method stub
		return conn.prepareStatement(sql);
	}
	
	
	@Override
	//需要加强的方法
	public void close() throws SQLException {
		//添加到连接池中
		System.out.println("前:"+list.size());
		//System.out.println(this);//this代表的是当前连接
		list.addLast(this);
		System.out.println("后:"+list.size());
		
		System.out.println("已经归还到连接池中");
	}
················································这里
···············································这里
······························还有这里都是调用原来的方法,很多哦
}

通过连接池来获取连接的时候··每次从list中拿出来conn的时候,使用装饰者模式将这个conn传给修饰类,再将返回的对象传给这里获取的conn,如下
自定义的数据库连接池:

public class MyDataSource {
	static LinkedList<Connection> pool=new LinkedList<>();
	static{
		//初始化的时候 需要放入3个连接
		for (int i = 0; i < 3; i++) {
			try {
				Connection conn = JdbcUtils.getConnection();
				pool.addLast(conn);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	//从连接池中获取连接
	public static Connection getConnection(){
		//获取连接的时候需要判断list是否为空
		if(pool.isEmpty()){
			//在添加2个连接进去
			for (int i = 0; i < 3; i++) {
				try {
					Connection conn = JdbcUtils.getConnection();
					pool.addLast(conn);
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println("从池中获取一个连接");
		 Connection conn = pool.removeFirst();
		 //将conn进行包装 
		 // ConnectionWarp myConn = new ConnectionWarp(conn);
		 ConnectionWarp myConn = new ConnectionWarp(conn,pool);
		return myConn;
	}
}

然后到这里就结束了,这篇文章送给我自己,生日快乐~~~~~嘻嘻嘻。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值