MySQL---当Java遇上MySQL⑦---我的连接池改进,动态代理模式。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34928644/article/details/82799611

由于 我的连接池普通版 中连接池版本二中,虽然修改了close方法,但是其它代码太多了。这时候应该考虑采用动态代理模式来开发。

动态代理模式

采用动态代理的前提:被代理的对象必须实现某个接口,而且调用该对象是面向接口的方式。相关文档

接口:IPerson

package cn.hncu.proxy;

public interface IPerson {
	public abstract void sayHello();
}

实现类:Person

package cn.hncu.proxy;

public class Person implements IPerson {
	
	@Override
	public void sayHello() {
		System.out.println("Hello world");
	}
	
	public int sum(int a,int b) {
		return a+b;
	}
	
}

演示代理模式

package cn.hncu.proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;

/*
 * 演示动态代理
 */
public class ProxyDemo {
	
	//回顾:类反射调用一个方法
	@Test
	public void demo1() throws Exception {
		
		/*
		 * 实现:
		 * IPerson p = new Person();
		 * int sum = p.sum(10,20);
		 */
		//1.获取类模版
		Class<Person> clazz = Person.class;
		//2.获取想要调用的方法对象
		//第一个参数:方法名,第二个参数:该方法的参数类型
		Method method = clazz.getMethod("sum", new Class[]{ int.class,int.class});
		//3.获取调用该方法的对象
		//3.1获取空参构造器
		Constructor<Person> constructor = clazz.getConstructor(new Class[]{});
		//3.2 通过空参构造器创建一个空参实例
		Person obj = constructor.newInstance(new Object[]{});
		//4.调用该方法
		Object[] args = {10,20}; //参数
		Object returnValue = method.invoke(obj, args);
		System.out.println("a+b="+returnValue); 
	}
	
	//演示动态代理
	@Test
	public void dynamicProxy() {
		final Person p = new Person();
		//技术入口: java.lang.reflect.Proxy类的newProxyInstance方法
		Object proxiedObj = Proxy.newProxyInstance(
								ProxyDemo.class.getClassLoader(), 
								new Class[]{IPerson.class}, 
								new InvocationHandler() {
									//参数1:代理对象,与proxiedObj相同,参数2:被调用的方法对象,参数3:被调用的方法的参数
									@Override
									public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
										/* 当 person 代理对象调用sayHello()方法时,
										 * 就会调用到 invoke 这个方法
										 */
										
										System.out.println("代理对象,在前面做了一些功能");
										
										//如果只有下面这一句,则采用的原型对象 p 的 sayHello()方法
										Object returnValue = method.invoke(p, args); 
										
										//如果不满意的花可以补充些东西或者不调用 "原型对象" 的方法
										
										System.out.println("代理对象,在后面做了一些功能");
										
										return returnValue;
									}
								});
		IPerson person = (IPerson) proxiedObj;
		person.sayHello();
	}
	
}

动态代理之连接池

采用动态代理的方式既能修改con.close()方法,而且代码量也少,可见动态代理开发模式相当有用。

配置文件信息:

#MySQL
driver=com.mysql.jdbc.Driver
#url=jdbc:mysql://127.0.0.1:3306/hncu?useUnicode=true&characterEncoding=utf-8
#下面这一句等价于上面这一句 ,因为 第三个 '/'代表默认路径即'127.0.0.1:3306'
url=jdbc:mysql:///hncu?useUnicode=true&characterEncoding=utf-8
username=root
password=1234
size=4

代码

package cn.hncu.utils;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.Queue;

/*
 * 采用动态代理的方式实现线程池
 */
public class MyConnPool3 {
	private static Queue<Connection> pool = new LinkedList<Connection>();
	private static int size = 3;
	static {
		Properties p = new Properties();
		try {
			//加载配置文件
			p.load( MyConnPool3.class.getClassLoader().getResourceAsStream("myConnPool.properties"));
			//读取配置信息
			String driver = p.getProperty("driver");
			String url = p.getProperty("url");
			String username = p.getProperty("username");
			String password = p.getProperty("password");
			String strSize = p.getProperty("size");
			size = Integer.valueOf( strSize );
			//加载驱动
			Class.forName( driver );
			for( int i = 0; i < size; i++ ) {
				//因为匿名内部类需要调用该对象,所以用final修饰
				final Connection con = DriverManager.getConnection(url, username, password);
				//关键点
				//这是一个 Connection 接口的代理对象
				Object proxiedObj = Proxy.newProxyInstance(
										MyConnPool3.class.getClassLoader(), 
										new Class[] {Connection.class},
										new InvocationHandler() { //这个才是关键点
											//参数 proxy对象 就是proxiedObj对象, method就是被调用的方法对象 , args方法参数
											@Override
											public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
												//判断被调用的方法是否是close()方法
												if( "close".equals( method.getName() ) ) {
													//修改close()方法
													pool.add( (Connection) proxy );
													System.out.println("还回来一个conn...");
													return null;
												}
												return method.invoke(con, args);
											}
										});
				Connection con2 = (Connection) proxiedObj;
				pool.add(con2);
			}
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage(), e);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e.getMessage(), e);
		} catch (SQLException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	/**
	 * 获取数据库连接对象
	 * @return 数据库连接对象
	 */
	public synchronized static Connection getConnection() {
		if( pool.size() <= 0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return getConnection();
		}
		return pool.poll();
	}
	
}

源码

源码链接

猜你喜欢

转载自blog.csdn.net/qq_34928644/article/details/82799611