数据库连接池代理实现(代理设计模式)-续数据库连接池

时间:2022-12-11 14:58:39
在代码中调用close时也可以还连接

对close方法进行修改。


类加载器

数据库连接池代理实现(代理设计模式)-续数据库连接池
数据库连接池代理实现(代理设计模式)-续数据库连接池
系统加载字节码是从下层往上层找的  如果父类没有就继续找父类 找到根加载器之后再往下加载    系统不允许操作根加载器  所以返回值永远是null、

动态代理

作用:
1:对某个方法增强。
2:在不污染源类的情况下,修改原类的行为。
代理类,与被代理类,两个不同的实体。
要求:
所有被代理的类,都必须要拥有一个接口。

本质上是对方法进行修改,但其实它是通过反射执行的某个方法。

动态代理的核心类

Proxy – 用于创建给定接口的子类,在内存中动态的创建。$Proxy0. - 此类只使用一次。
InovocationHandler – 执行句柄。在执行时可以获取被代理类的所有反射。 - 用户的每一次调用都会被这个句柄拦截到。

代理举例

被代理类实现的接口
public interface IGDG {
String talk();
}


被代理类
public class GDG implements IGDG {
int nu = 0;
public GDG(int nm) {
nu=nm;
}
public String talk(){
System.err.println("5.1:开始讲了....."+nu);
return "你好:"+nu;
}
}





代理实现
public class ProxyDemo {
public static void main(String[] args) throws Exception {
final Object o = new GDG(3);//匿名内部类只能访问final成员
System.err.println("o1 is:"+o+","+o.getClass());//GDG@4a5ab2,class cn.itcast.demo.GDG
//使用Proxy类创建IGDG接口的子类
Object proxyedObj =
Proxy.newProxyInstance(ProxyDemo.class.getClassLoader(), //用哪一个类加载器在内存中加载一个IGDG的子类
new Class[]{IGDG.class},//创建哪些接口的子类
new InvocationHandler(){
public Object invoke(Object proxy,
Method method, Object[] args)
throws Throwable {
System.err.println("你正在执行的方法名为:"+method.getName());
Object returnValue = method.invoke(o,args);
return returnValue;
}
});
//将proxyedObj强转成IGDG
IGDG o2 = (IGDG) proxyedObj;
o2.talk();
System.err.println("-------");
System.err.println("o2 is:"+o2+","+o2.getClass());
}




仔细讲解
public class ProxyDemo2 {
public static void main(String[] args) throws Exception {
final GDG o = new GDG(4);
System.err.println("1:声明被代理的对象"+o+","+o.getClass());
Object proxyedObj =
Proxy.newProxyInstance(
ProxyDemo2.class.getClassLoader(),
new Class[]{IGDG.class},//必须填接口
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.err.println("5:正在调用的方法是:"+method.getName());//talk
Object returnValue = method.invoke(o,args);
System.err.println("6:通过反射调用目标(被代理类)类的方法成功,返回值是:"+returnValue);
return "你不好";
}
}
);

System.err.println("2:代理类创建完成:"+proxyedObj.getClass());
System.err.println("3:强转成IGDG接口");
IGDG o2 = (IGDG) proxyedObj;
System.err.println("4:调用代理类的talk方法");
String back = o2.talk();
System.err.println("7:方法都调用完成\t"+back);
}
}



输出结果
1:声明被代理的对象cn.itcast.demo.GDG@1c68b6f,class cn.itcast.demo.GDG
2:代理类创建完成:class com.sun.proxy.$Proxy0
3:强转成IGDG接口
4:调用代理类的talk方法
5:正在调用的方法是:talk
5.1:开始讲了.....4
6:通过反射调用目标(被代理类)类的方法成功,返回值是:你好:4
7:方法都调用完成你不好


代理list

public class ListProxy {
public static void main(String[] args) throws Exception {
final List list = new ArrayList();
//声明代理
Object oo = Proxy.newProxyInstance(
ListProxy.class.getClassLoader(),
new Class[]{List.class}
,
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//执行被代理类的方法
System.err.println("正在执行的方法是:"+method.getName());
if(args!=null){
for(Object arg:args){
System.err.println("参数:"+arg);
}
}
Object returnVal = method.invoke(list,args);
if(method.getName().equals("size")){//调用的是否是size方法
System.err.println("其实是:"+returnVal);
return 1000;
}
return returnVal;
}
});

List list2 = (List) oo;
//list2.add("Jack");
//
//int size = list2.size();
//System.err.println("大小是:"+size);
//
System.err.println("-----------");
list.add("Rose");//1
list.add("Jack");
System.err.println("=====================");
int size = list2.size();
System.err.println("大小是:"+size);//1
}
}


数据库连接池代理实现(代理设计模式)-续数据库连接池

代理的任务

1:在内存中创建某个接口的子类。
2:拦截所有在代理上执行的方法。( 除了getClass方法。)

用动态代理书写连接池

设计:
代理的目标:原生的connection。
  代理的目的:修改close方法,让close方法不可以关闭连接,且主动收回连接。

通过动态代理,和线程通讯:
1:对Cxonnection进行代理。
 2:在获取Connection时,通过同步,如果没有连接时,就让线程进入等待池。
 3:修改close方法,且在还了连接以后唤醒正在等待的线程。


public class ConnUtils4 {
//第一步:声明连接池维护所有的连接
private static List<Connection> pool = new ArrayList<Connection>();
//第二步:静态代码块中创建多个连接
static{
try{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql:///db909?characterEncoding=UTF8";
for(int i=0;i<3;i++){
final Connection con = DriverManager.getConnection(url,"root","1234");//com.mysql.jdbc.Jdbc4Connection@
//对con对象进行动态代理
Object proxyedCon =
Proxy.newProxyInstance(
ConnUtils4.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;
}
}
}