• java动态代理之CGLIB实现


    动态代理(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);
        }
    
    }
  • 相关阅读:
    Ecommerce 3.0雏形出现
    网上购物折扣如此红火
    [ZZ]将测试人员整合到敏捷团队中
    晒工资网——Glassdoor
    [ZZ].NET自动探索式测试工具——Pex
    [ZZ]好的测试应该具备哪些特质?
    我用到的Firefox插件
    [ZZ]WatiN & Selenium RC-自动化测试工具比较
    [ZZ]高盛:Amazon预计10年营收涨10倍达台币3兆元
    从优惠券到维络卡
  • 原文地址:https://www.cnblogs.com/ywbmaster/p/9797926.html
Copyright © 2020-2023  润新知