java動態代理之CGLIB實現
阿新 • • 發佈:2018-10-16
ssl return 其他 ase ger pac 父類 linked nic
動態代理(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實現