如果你不太清楚装饰者模式,请看我的另一篇简短的文章: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);得到的,而aDriver是registeredDrivers最终集合中的一个元素。所以我们要清楚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就知道是谁了吧。就是fms即FabricMySQLDriver
那么最后了,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;
}
}
然后到这里就结束了,这篇文章送给我自己,生日快乐~~~~~嘻嘻嘻。