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

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

  1. Java动态代理与CGLib

    Java帝国之动态代理 CGLib:从兄弟到父子-动态代理在民间是怎么玩的? 以上两篇文章引用自微信公众号: 码农翻身 Java动态代理 深度详解 以上文章引用博客园:陈树义

  2. Java动态代理与Cglib库

    JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...

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

    <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        / ...

  4. Java动态代理机制——Cglib

    上一篇说过JDK动态代理机制,只能代理实现了接口的类,这就造成了限制.对于没有实现接口的类,我们可以用Cglib动态代理机制来实现. Cglib是针对类生成代理,主要是对用户类生成一个子类.因为有继承 ...

  5. IT忍者神龟之Java动态代理与CGLib代理

    <br>public class UserDAOImpl{ <br><br>    public void save() { <br>        / ...

  6. java动态代理--proxy&cglib

    大纲 代理 proxy cglib 小结 一.代理 为什么要用代理?其实就是希望不修改对象的情况下,增强对象. 静态代理: 静态代理模式,需要代理类和目标类实现同一接口,代理类的方法调用目标类的方法, ...

  7. Proxy Pattern(Java动态代理和cglib的实现)

    代理模式:给某一个对象提供代理对象,由代理对象控制具体对象的引用. 代理,指的就是一个角色对表另一个角色采取行动,就生活中,一个红酒厂商,是不会直接把红酒零销给客户的,都是通过代理完成他的销售业务.而 ...

  8. 深入浅出Java动态代理

    文章首发于[博客园-陈树义],点击跳转到原文深入浅出Java动态代理 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理 ...

  9. Java动态代理 深度详解

    代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理模式从类型上来说,可以分为静态代理和动态代理两种类型. 今天我将用非常 ...

随机推荐

  1. 8.9 day30 并发编程 进程理论 进程方法 守护进程 互斥锁

    多道技术 1.空间上的复用 多个程序共用一套计算机硬件 多道技术原理 2.时间上的复用 ​ 切换+保存状态 ​ 1.当一个程序遇到IO操作 操作系统会剥夺该程序的CPU执行权限( 提高了CPU的利用率 ...

  2. JS实现循环删除数组中元素的方法介绍

    这篇文章主要给大家介绍了关于Javascript循环删除数组中元素的几种方法,文中给出了详细的示例代码供大家参考学习,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧. 本文主要跟大家分享了 ...

  3. JDK集合面试20问

    1. HashMap的内部实现原理是什么? HashMap内部实现原理是数组+链表,通过散列算法将key值散列到数组中,如果到相同的位置,则通过拉链法解决散列冲突.在JDK8中新增了红黑树结构,当Ha ...

  4. 手撕ThreadPoolExecutor线程池源码

    这篇文章对ThreadPoolExecutor创建的线程池如何操作线程的生命周期通过源码的方式进行详细解析.通过对execute方法.addWorker方法.Worker类.runWorker方法.g ...

  5. 学习 Object-C: 简史

    对于一门语言的历史,我认为写一本书可能都不为过,关键是看你如何介绍和表达.当然每一个人的理解也大相径庭.本文阐述也仅仅只是冰山一角,如果需要深入了解,自己可能需要多花费一些心思. 这里也不会给大家说太 ...

  6. HDU 6363

    题意略. 思路: 这里有两个结论需要注意: 1.gcd(a ^ x - 1,a ^ y - 1) = a ^ gcd(x,y) - 1 2.gcd(fib[x],fib[y]) = fib[gcd(x ...

  7. CSU1784

    题意略. 思路:为了更好地求出一段连续数字的异或和,我们可以用前缀异或和来维护,现在我们只需要考虑每一个在数组中的数字向前异或,且在指定范围内, 异或值为全1的个数有多少个.算出每一个位子能做出的贡献 ...

  8. Linux 防火墙开放、查询、关闭端口

    1. 开放指定端口 firewall-cmd --zone=public --add-port=5121/tcp --permanent # --permanent 永久生效,如果不加此条,重启后该命 ...

  9. MSIL实用指南-比较运算

    数值的比较就是大于.小于.等于.大于等于.小于等于.不等于,它们的运算结果都是布尔值.大于.小于.等于有直接对应的指令,分别是Cgt.Clt.Ceq.大于等于.小于等于.不等于没有直接对应的指令,它的 ...

  10. Nginx总结(四)基于域名的虚拟主机配置

    前面讲了如何安装配置Nginx,大家可以去这里看看nginx系列文章:https://www.cnblogs.com/zhangweizhong/category/1529997.html 今天要说的 ...