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

最新文章

  1. Spark核心——RDD
  2. java 28 - 1 设计模式 之 面向对象思想设计原则和模版设计模式概述
  3. 解决Cannot find MySQL header files under /usr/include/mysql的错误
  4. JS 生成26个大小写字母
  5. php文件上传之多文件上传
  6. YUM Installation PostgreSQL
  7. Javascript继承实现
  8. http://www.cnblogs.com/amboyna/archive/2008/03/08/1096024.html
  9. 详解Android ActionBar之二:ActionBar添加Tabs标签和下拉导航
  10. C# Json处理日期和Table
  11. 数据库Mysql性能优化
  12. java里遍历map的常见方式
  13. python 学习网站
  14. Windows系统重装
  15. Word2Vec总结
  16. Confluence 6 通过 SSL 或 HTTPS 运行 - 创建或请求一个 SSL 证书
  17. linux清除缓存
  18. Numpy:ndarray数据类型和运算
  19. Hadoop生态圈-Kafka配置文件详解
  20. 十三oracle --控制结构(分支,循环,控制)

热门文章

  1. ASP.NET CORE 2.* 利用集成测试框架覆盖HttpClient相关代码
  2. 性能测试学习第七天-----JMeter之linux环境部署篇
  3. 一文搞懂Python可迭代、迭代器和生成器的概念
  4. Appium+Python+Genymotion ------环境配置
  5. 关于多线程中sleep、join、yield的区别
  6. LightOJ - 1370 Bi-shoe and Phi-shoe 欧拉函数 题解
  7. POJ 3186
  8. 04_枚举类型iota
  9. 本地搭建持续集成(AzureDevops)
  10. poj 1127 -- Jack Straws(计算几何判断两线段相交 + 并查集)