版权声明:本文为博主原创文章,未经博主允许不得转载。 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();
}
}