由于 我的连接池普通版 中连接池版本二中,虽然修改了close方法,但是其它代码太多了。这时候应该考虑采用动态代理模式来开发。
动态代理模式
采用动态代理的前提:被代理的对象必须实现某个接口,而且调用该对象是面向接口的方式。相关文档
接口:IPerson
package cn.hncu.proxy;public interface IPerson {public abstract void sayHello();
}
实现类:Person
package cn.hncu.proxy;public class Person implements IPerson {@Overridepublic 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 {//回顾:类反射调用一个方法@Testpublic 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); }//演示动态代理@Testpublic 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:被调用的方法的参数@Overridepublic 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方法参数@Overridepublic 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();}}