>>分享Java编程技术,对《Java面向对象编程》等书籍提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 28637 个阅读者 刷新本主题
 * 贴子主题:  动态代理(CGLIB 与连接池的案例) 回复文章 点赞(0)  收藏  
作者:日月光华    发表时间:2019-11-04 19:36:05     消息  查看  搜索  好友  邮件  复制  引用

动态代理(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());
    }
}

  运行结果:
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

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);
    }

}

程序猿的技术大观园:www.javathinker.net
  Java面向对象编程-->Swing组件(下)
  JavaWeb开发-->自定义JSP标签(Ⅰ)
  JSP与Hibernate开发-->Java应用分层架构及软件模型
  Java网络编程-->用Swing组件展示HTML文档
  精通Spring-->绑定表单
  Vue3开发-->Vue指令
  Java虚拟机安全性-class文件检验器
  BIO和NIO区别
  TCP、UDP及Socket代码示例
  用注解去代替if-else的技巧
  请求大佬们的帮助
  volatile 实现原理
  深入分析synchronized实现原理
  JNI_Java Native Interface的用法
  正则表达式基础入门
  Java设计模式:装饰器模式
  Socket服务器的整体架构
  5个非常有挑战性的Java面试题
  Java入门实用代码:使用 Enumeration 遍历 HashTable
  Java入门实用代码:字符串替换
  初学者该学哪种编程语言
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。