JDK动态代理实现数据库连接池

连接池

首先创建连接池类

@Setter
public class ConnectionPool {

    /**
     * 连接池(存放连接的集合)
     *
     */
    private LinkedList<Connection> pool = new LinkedList<>();
    /**
     * 连接属性
     */
    private String url;
    private String user;
    private String password;
    /**
     * 池大小
     */
    private Integer poolSize;

    /**
     * 在构造方法中初始化连接池
     */

    public void init() {
        for(int i=0; i<poolSize; i++) {
            try {
                //1.从数据库获取连接对象
                Connection conn = DriverManager.getConnection(url, user, password);
                //2.对连接对象创建代理
                conn = createProxy(conn);
                //3.将代理过的连接对象保存到池中
                pool.add(conn);
            } catch (SQLException e) {
                throw new RuntimeException("Init connection pool error.", e);
            }
        }
    }

    /**
     * 为连接对象创建代理
     * @param connection
     * @return
     */
    private Connection createProxy(Connection connection) {
        //创建回调处理器
        InvocationHandler handler = new ConnectionInvocationHandler(connection, pool);
        //获取连接对象的所有接口
        Class<?>[] interfaces = new Class[]{Connection.class};
        //获取类加载器
        ClassLoader loader = ConnectionPool.class.getClassLoader();
        //创建代理
        connection = (Connection) Proxy.newProxyInstance(loader, interfaces, handler);
        return connection;
    }

    /**
     * 从池里面获取代理连接
     * @return
     */
    public Connection getConnection() {
        return pool.removeFirst();
    }

    /**
     * 查看连接池的大小
     * @return
     */
    public int size() {
        return pool.size();
    }
}

连接对象配置文件

url = jdbc:mysql://localhost:3306/city?useSSL=false
username = root
password = root
poolSize = 5

动态代理执行的回调处理器

public class ConnectionInvocationHandler implements InvocationHandler {
    /**
     * 目标对象(被代理的连接对象)
     */
    private Connection connection;

    /**
     * 连接池
     */
    private LinkedList<Connection> pool;

    public ConnectionInvocationHandler(Connection connection,
                                       LinkedList<Connection> pool) {
        this.connection = connection;
        this.pool = pool;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //如果当前调用的是Connection的close方法则将它放回到池中
        if("close".equals(method.getName())) {
            //从池的尾部放回去
            //注意:这里放回池中的必须是代理对象,而不是目标Connection
            pool.addLast((Connection) proxy);
            return null;
        } else {
            //除close以外的其他方法则正常调用目标的行为
            return method.invoke(connection, args);
        }
    }
}

配置类

配置类,将连接池放到容器中

@Slf4j
public class AppConfig {

    @Value("${url}")
    private String url;
    @Value("${username}")
    private String user;
    @Value("${password}")
    private String password;
    @Value("${poolSize}")
    private Integer poolSize;

    /**
     * 装配连接池
     * @return
     */
    @Bean
    public ConnectionPool connectionPool() {
        log.info("url: " + url);
        log.info("user: " + user);
        log.info("pwd: " + password);
        log.info("size: " + poolSize);
        //创建连接池并设置相关属性
        ConnectionPool pool = new ConnectionPool();
        pool.setUrl(url);
        pool.setUser(user);
        pool.setPassword(password);
        pool.setPoolSize(poolSize);
        //初始化连接池
        pool.init();
        return pool;
    }
}

测试

@Slf4j
public class Main {

    public static void main(String[] args) throws SQLException {
        //创建容器
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        //从容器中获取连接池
        ConnectionPool pool = context.getBean(ConnectionPool.class);
        log.info("连接数:" + pool.size());
        Connection conn1 = pool.getConnection();
        Connection conn2 = pool.getConnection();
        log.info("连接数:" + pool.size());
        conn1.close();
        conn2.close();
        log.info("连接数:" + pool.size());
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值