动态代理(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.6 day27 网络编程 osi七层协议 Time模块补充知识 TCP协议

    Time模块补充知识 date和datetime区别是什么? date 就是年月日 datetime就是年月时时分秒 以下代码为什么会报错? import json from datetime imp ...

  2. java读取本机磁盘及遍历磁盘文件

    1. 获取本机所有盘符信息 //1. 获取本机盘符 File[] roots = File.listRoots(); for (int i = 0; i < roots.length; i++) ...

  3. Element-UI 2.4.11 版本 使用注意(发现一点更新一点)

    1.$Vue.$refs.addForm.resetFields() 的resetFields()方法重置到默认值并不是 ,你在form绑定对象上写的默认值 ,而是这个form被渲染出来之后第一次赋到 ...

  4. Go_笔试题记录-不熟悉的

    1.golang中没有隐藏的this指针,这句话的含义是() A. 方法施加的对象显式传递,没有被隐藏起来 B. golang沿袭了传统面向对象编程中的诸多概念,比如继承.虚函数和构造函数 C. go ...

  5. es6 个人笔记

           1.package.json==>npm init node_modules==>npm install webpack -D webpack.config.js==> ...

  6. POJ 1661 暴力dp

    题意略. 思路: 很有意思的一个题,我采用的是主动更新未知点的方式,也即刷表法来dp. 我们可以把整个路径划分成横向移动和纵向移动,题目一开始就给出了Jimmy的高度,这就是纵向移动的距离. 我们dp ...

  7. three.js实现球体地球城市模拟迁徙

    概况如下:1.SphereGeometry实现自转的地球:2.THREE.ImageUtils.loadTexture加载地图贴图材质:3.THREE.Math.degToRad,Math.sin,M ...

  8. springboot--事务的使用

    @Transactional原理 事务是一些sql语句对数据库操作的集合,因此如果在一个Java方法里涉及了对数据库的操作,业务需要的话我们就可以考虑把这些操作作为一个事务.通过在方法上加个@Tran ...

  9. P3225 [HNOI2012]矿场搭建 割点 tarjan 双联通分量

    https://www.luogu.org/problemnew/show/P3225 题意 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条 ...

  10. P1613 跑路 倍增思想 + 邻接矩阵

    题意 给定一个有向图,每条边的花费为1.现在有一个空间跑路器,可以走2^k长度的路,只用花1秒的时间.问从1走到n最少的时间.n <= 50, k <= 64. 思路 这道题说是倍增,但是 ...