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

}

原文地址:https://www.cnblogs.com/ywbmaster/p/9797926.html

时间: 2024-08-30 01:47:39

java动态代理之CGLIB实现的相关文章

(转)Java动态代理与CGLib代理

本文通过spring aop的代理实现简述了java动态代理和cglib的区别,有助于理解java的代理模式 转载自:http://www.iteye.com/topic/182654 Java代码 <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        // TODO Auto-generated method stub <br>        Sys

Java动态代理、CGLIB动态代理

开篇 Java 的代理就是客户类不再直接和委托类打交道, 而是通过一个中间层来访问, 这个中间层就是代理.为啥要这样呢, 是因为使用代理有 2 个优势: 可以隐藏委托类的实现 可以实现客户与委托类之间的解耦, 在不修改委托类代码的情况下能够做一些额外的处理 我们举个很常见的例子: 工厂会生产很多的玩具, 但是我们买玩具都是到商店买的, 而不是到工厂去买的, 工厂怎么生产我们并不关心, 我们只知道到商店可以买到自己想要的玩具,并且,如果我们需要送人的话商店可以把这些玩具使用礼品盒包装.这个工厂就是

Java动态代理与Cglib库

JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务.  按照代理的创建时期,代理类可以分为两种.  静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. 

Java动态代理 深度详解

代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理模式从类型上来说,可以分为静态代理和动态代理两种类型. 今天我将用非常简单易懂的例子向大家介绍动态代理的两种类型,接着重点介绍动态代理的两种实现方式(Java 动态代理和 CGLib 动态代理),最后深入剖析这两种实现方式的异同,最后说说动态代理在我们周边框架中的应用. 在开始之前,我们先假设这样一个场景:有一个蛋糕店,它们都是使用蛋糕机来做蛋糕的,而且不同种类的蛋糕

Java进阶之 JDK动态代理与Cglib动态代理

一.动态代理概述: 与静态代理对照(关于静态代理的介绍 可以阅读上一篇:JAVA设计模式之 代理模式[Proxy Pattern]), 动态代理类的字节码是在程序运行时由Java反射机制动态生成. 注意: 1.AspectJ是采用编译时生成AOP代理类,具有更好的性能,但是需要使用特定的编译器进行处理 2.Spring AOP采用运行时生成AOP代理类,无需使用特定编译器进行处理,但是性能相对于AspectJ较差 二.JDK动态代理 [对有实现接口的对象做代理] 1.JDK动态代理中 需要了解的

Java学习之:JDK动态代理与CGLIB动态代理

代理的概念:简单的理解就是通过为某一个对象创建一个代理对象,我们不直接引用原本的对象,而是由创建的代理对象来控制对原对象的引用. 动态代理:是指在程序运行时由Java反射机制动态生成,无需手动编写代码.动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类. 代理原理:代理对象内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象.同时,代理对象可以在执行真实对象操作时,附加其他的操作

java动态代理(JDK和cglib)

转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,

代理模式 &amp; Java原生动态代理技术 &amp; CGLib动态代理技术

第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务.(其实就是在代理类中关联一个委托类的实例,然后在代理类中进行包装). UML图如下: 第二部分.在Java中实现代理模式  按照代理的创建时期,代理类可以分

《转》java动态代理(JDK和cglib)

该文章转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建