动态代理(CGlib 与连接池的案例)
Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用。
我们要使用cglib代理必须引入 cglib的jar包
<dependencies> <!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.8</version> </dependency> </dependencies>
定义一个UserService的普通类
public class UserService { public void add(){ System.out.println("添加用户"); } public void findUser(){ System.out.println("查找用户"); } }
定义一个方法拦截器,类似于JDK中的InvocationHandler
/*private Object target; public UserServiceInterceptor(Object target){ this.target = target; }*/ /** * 拦截方法 * @param proxy 代理对象 * @param method 目标对象正在调用的方法 * @param args 目标对象方法所需的参数 * @param methodProxy 目标对象方法的代理实例 * @return * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before..."); //Object returnVal = method.invoke(target, args); //使用methodProxy来回调父类的方法,第一个参数是代理对象,第二个参数是目标方法所需的参数 Object returnVal = methodProxy.invokeSuper(proxy, args); System.out.println("after..."); return returnVal; }
2.1连接池
定义一个DBUtil类:
public class DBUtil { private static String driver = "com.mysql.jdbc.Driver"; private static String url = "jdbc:mysql://localhost:3306/homework?useSSL=true&useUnicode=true&characterEncoding=utf-8"; private static String user = "root"; private static String password = "root"; static { try { Class.forName(driver); } catch (ClassNotFoundException e) { throw new RuntimeException(e.getMessage()); } } public static Connection getConnection(){ try { return DriverManager.getConnection(url, user, password); } catch (SQLException e) { throw new RuntimeException(e.getMessage()); } }
定义一个连接池的类:
public class ConnectionPool { /** * 连接池集合 */ private static LinkedList<Connection> pool = new LinkedList<>(); /** * * @param initSize 初始化连接池的大小 */ public ConnectionPool(int initSize){ for(int i= 0; i<initSize; i++){ //从数据库获取一个连接对象 Connection conn = DBUtil.getConnection(); //将这个conn对象进行一层代理 conn = proxyConnection(conn); //放入连接池,返给池中的是一个代理的对象 pool.add(conn); } } /** * 给Connection对象创建代理实例 * @return */ private Connection proxyConnection(Connection conn){ Object proxy = Proxy.newProxyInstance(conn.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果当前调用的是close方法,则将连接放回连接池 if("close".equals(method.getName())){ //注意:pool放入的是代理对象,不是conn这个目标对象 pool.addLast((Connection) proxy); return null; } //除close方法以外的其他方法正常调用 return method.invoke(conn, args); } }); return (Connection) proxy; } /** * 提供一个从连接池获取连接的方法 * @return */ public Connection getConnection(){ if(pool.size() > 0){ return pool.removeFirst(); } throw new RuntimeException("连接池无可用连接"); } /** * 查看连接池大小的方法 * @return */ public int size(){ return pool.size(); } }
测试Main方法
public class Main { public static void main(String[] args) throws SQLException { ConnectionPool pool = new ConnectionPool(10); System.out.println("当前连接池大小: "+pool.size()); Connection conn = pool.getConnection(); System.out.println("当前连接池大小: "+pool.size()); conn.close(); System.out.println("当前连接池大小: "+pool.size()); } }
运行结果:
2.2利用动态代理实现数据库连接池的操作
package mybatis.tools; 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; /** * 自定义连接池, 管理连接 * 代码实现: 1. MyPool.java 连接池类, 2. 指定全局参数: 初始化数目、最大连接数、当前连接、 连接池集合 3. 构造函数:循环创建3个连接 4. 写一个创建连接的方法 5. 获取连接 ------> 判断: 池中有连接, 直接拿 ------> 池中没有连接, ------> 判断,是否达到最大连接数; 达到,抛出异常;没有达到最大连接数, 创建新的连接 6. 释放连接 -------> 连接放回集合中(..) * */ /** * 描述: * 连接池 * * @author lance * @create 2018-10-15 14:58 */ public class MyPool { // 初始化连接数目 private int init_count = 3; // 最大连接数 private int max_count = 6; // 记录当前使用连接数 private int current_count = 0; // 连接池 (存放所有的初始化连接) private LinkedList<Connection> pool = new LinkedList<Connection>(); //1. 构造函数中,初始化连接放入连接池 public MyPool() { // 初始化连接 for (int i=0; i<init_count; i++){ // 记录当前连接数目 current_count++; // 创建原始的连接对象 Connection con = createConnection(); // 把连接加入连接池 pool.addLast(con); } } /** * 2. 创建一个新的连接的方法 */ private Connection createConnection(){ try { Class.forName("com.mysql.jdbc.Driver"); // 原始的目标对象 final Connection con = DriverManager.getConnection("jdbc:mysql:///mydb", "root", "root"); /**********对con对象代理**************/ // 对con创建其代理对象 Connection proxy = (Connection) Proxy.newProxyInstance( // 类加载器 con.getClass().getClassLoader(), // 当目标对象是一个具体的类的时候 //con.getClass().getInterfaces(), // 目标对象实现的接口 new Class[]{Connection.class}, // 当调用con对象方法的时候, 自动触发事务处理器 new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法返回值 Object result = null; // 当前执行的方法的方法名 String methodName = method.getName(); // 判断当执行了close方法的时候,把连接放入连接池 if ("close".equals(methodName)) { System.out.println("begin:当前执行close方法开始!"); // 连接放入连接池 (判断..) pool.addLast(con); System.out.println("end: 当前连接已经放入连接池了!"); } else { // 调用目标对象方法 result = method.invoke(con, args); } return result; } } ); return proxy; } catch (Exception e) { throw new RuntimeException(e); } } /** * 3. 获取连接 */ public Connection getConnection(){ // 3.1 判断连接池中是否有连接, 如果有连接,就直接从连接池取出 if (pool.size() > 0){ return pool.removeFirst(); } // 3.2 连接池中没有连接: 判断,如果没有达到最大连接数,创建; if (current_count < max_count) { // 记录当前使用的连接数 current_count++; // 创建连接 return createConnection(); } // 3.3 如果当前已经达到最大连接数,抛出异常 throw new RuntimeException("当前连接已经达到最大连接数目 !"); } /** * 4. 释放连接 */ public void realeaseConnection(Connection con) { // 4.1 判断: 池的数目如果小于初始化连接,就放入池中 if (pool.size() < init_count){ pool.addLast(con); } else { try { // 4.2 关闭 current_count--; con.close(); } catch (SQLException e) { throw new RuntimeException(e); } } } public static void main(String[] args) throws SQLException { MyPool pool = new MyPool(); System.out.println("当前连接: " + pool.current_count); // 使用连接 //pool.getConnection(); pool.getConnection(); Connection con4 = pool.getConnection(); Connection con3 = pool.getConnection(); Connection con2 = pool.getConnection(); Connection con1 = pool.getConnection(); con1.close(); con2.close(); con3.close(); // 再获取 //pool.getConnection(); //pool.getConnection(); System.out.println("连接池:" + pool.pool.size()); System.out.println("当前连接: " + pool.current_count); } }
原文地址:https://www.cnblogs.com/ywbmaster/p/9797926.html
时间: 2024-08-30 01:47:39