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

在代码中调用close时也可以还连接

对close方法进行修改。


类加载器


数据库连接池代理实现(代理设计模式)-续数据库连接池_第1张图片
系统加载字节码是从下层往上层找的  如果父类没有就继续找父类 找到根加载器之后再往下加载    系统不允许操作根加载器  所以返回值永远是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
	}
}


数据库连接池代理实现(代理设计模式)-续数据库连接池_第2张图片

代理的任务

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

用动态代理书写连接池

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

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


public class ConnUtils4 {
	//第一步:声明连接池维护所有的连接
	private static List pool = new ArrayList();
	//第二步:静态代码块中创建多个连接
	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;
		}
	}
}











你可能感兴趣的:(JDBC)