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);
} }
java动态代理之CGLIB实现的更多相关文章
- Java动态代理与CGLib
Java帝国之动态代理 CGLib:从兄弟到父子-动态代理在民间是怎么玩的? 以上两篇文章引用自微信公众号: 码农翻身 Java动态代理 深度详解 以上文章引用博客园:陈树义
- Java动态代理与Cglib库
JDK动态代理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在 ...
- (转)Java动态代理与CGLib代理
<br>public class UserDAOImpl{ <br><br> public void save() { <br> / ...
- Java动态代理机制——Cglib
上一篇说过JDK动态代理机制,只能代理实现了接口的类,这就造成了限制.对于没有实现接口的类,我们可以用Cglib动态代理机制来实现. Cglib是针对类生成代理,主要是对用户类生成一个子类.因为有继承 ...
- IT忍者神龟之Java动态代理与CGLib代理
<br>public class UserDAOImpl{ <br><br> public void save() { <br> / ...
- java动态代理--proxy&cglib
大纲 代理 proxy cglib 小结 一.代理 为什么要用代理?其实就是希望不修改对象的情况下,增强对象. 静态代理: 静态代理模式,需要代理类和目标类实现同一接口,代理类的方法调用目标类的方法, ...
- Proxy Pattern(Java动态代理和cglib的实现)
代理模式:给某一个对象提供代理对象,由代理对象控制具体对象的引用. 代理,指的就是一个角色对表另一个角色采取行动,就生活中,一个红酒厂商,是不会直接把红酒零销给客户的,都是通过代理完成他的销售业务.而 ...
- 深入浅出Java动态代理
文章首发于[博客园-陈树义],点击跳转到原文深入浅出Java动态代理 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理 ...
- Java动态代理 深度详解
代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理模式从类型上来说,可以分为静态代理和动态代理两种类型. 今天我将用非常 ...
随机推荐
- flink 1.7.2 安装详解
##flink 1.7.2 安装需要java环境 下载地址 https://flink.apache.org/downloads.html#1.单机版 #创建用户flinkuseradd flink ...
- [HNOI2008]玩具装箱toy(斜率优化dp)
前言 这是我写的第一道$dp$斜率优化的题目,$dp$一直都很菜,而且咖啡鸡都说了这是基础的东西,然而看别人对$dp$斜率优化一大堆公式又看不懂就老老实实做几道题目,这个比较实在 描述 给出$n$和$ ...
- [HNOI2009]双递增序列(动态规划,序列dp)
感觉这个题还蛮难想的. 首先状态特别难想.设\(dp[i][j]\)表示前i个数,2序列的长度为j的情况下,2序列的最后一个数的最小值. 其中1序列为上一个数所在的序列,2序列为另外一个序列. 这样设 ...
- Laravel框架内实现api文档:markdown转为html
前后端分离的工作模式于今是非常流行了,前后端工作的对接,就离开不了API文档的辅助. 根据自己以往的工作经历,以及了解的一些资讯,API文档的建立,无非以下几种方式: 1. word文档模板 2. 第 ...
- 用小程序·云开发两天搭建mini论坛丨实战
笔者最近涉猎了小程序相关的知识,于是利用周末时间开发了一款类似于同事的小程序,深度体验了小程序云开发模式提供的云函数.数据库.存储三大能力.关于云开发,可参考文档:小程序·云开发. 个人感觉云开发带来 ...
- 玩转VSCode插件之Remote-SSH
前言 每当更换电脑就要从新搭建一遍开发环境... 每当拉完最新代码程序在本地跑不起来的时候就要检查服务器和开发电脑的环境... 每当服务器上出Bug的时候就想如果可以能够调试服务器代码多好啊.. 你是 ...
- 基础部分之System、Object、Calendar、StringBuffer
System.out.println(obj)和 System.out.println(obj.toString())区别 public static void main(String[] args) ...
- 关于window.location.href 传中文参数 乱码问题
传中文查询乱码问题 则需要对要传的参数进行二次编码 例如 window.location.href ="/xx.jsp?name="+name+""; 这样子 ...
- PythonI/O进阶学习笔记_3.2面向对象编程_python的继承(多继承/super/MRO/抽象基类/mixin模式)
前言: 本篇相关内容分为3篇多态.继承.封装,这篇为第二篇 继承. 本篇内容围绕 python基础教程这段: 在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法.使 ...
- unity编辑器扩展_07(创建对话框,检测按钮的点击,点击按钮后提示信息,保存设置的数据,显示点击按钮后的处理的进度条信息)
代码: using UnityEditor;using UnityEngine; public class ChangeValue : ScriptableWizard { ...