java动态代理之CGLIB实现
Posted tags: 篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java动态代理之CGLIB实现相关的知识,希望对你有一定的参考价值。 Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用。 定义一个UserService的普通类 2.1连接池 定义一个DBUtil类: 定义一个连接池的类: 测试Main方法 运行结果:
以上是关于java动态代理之CGLIB实现的主要内容,如果未能解决你的问题,请参考以下文章 #yyds干货盘点# 设计模式之代理模式: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>
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;
}
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();
}
}
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);
}
}