jdk 動態代理模擬mybatis的快取機制
在學習jdk的動態代理的時候我們需要記住一個類java.lang.reflect.Proxy和一個介面java.lang.reflect.InvocationHandler。InvocationHandler將jdk對類的處理以方法引數的方式暴露給我們,這個方法是
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {},以下是三個引數的說明
proxy:代理物件
method:被代理物件的方法,即被實際訪問的方法
args:被實際訪問的方法的引數
這裡的關鍵就是method和args,我們可以對args和method進行處理,比如判斷方法的引數是否是和上次呼叫時的一模一樣,如果引數一樣,方法也一樣,那麼我們就可以從快取中去獲取結果,比如mybatis的快取就是這樣的,一下是模擬的整個過程!
專案結構
User.java
package com.ss.entity;
public class User {
private Long userId;
private String userName;
private String nickName;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
@Override
public String toString() {
return "User [userId=" + userId + ", userName=" + userName + ", nickName=" + nickName + "]";
}
public User(){
}
public User(Long userId, String userName, String nickName) {
this.userId = userId;
this.userName = userName;
this.nickName = nickName;
}
}
UserDao.java
package com.ss.dao;
import com.ss.entity.User;
public interface UserDao {
Integer createUser(User user);
Integer deleteUser(User user);
Integer updateUser(User user);
User retrieveUser(Long userId);
}
UserDaoImpl.java
package com.ss.dao;
import java.lang.reflect.Proxy;
import com.ss.db.Cache;
import com.ss.db.DBProcess;
import com.ss.db.MySQL;
import com.ss.entity.User;
public class UserDaoImpl implements UserDao {
/**
* 通過proxy生成的DBProcess的代理物件
* new Cache(new MySQL())是關鍵
*/
private DBProcess proxy = (DBProcess) Proxy.newProxyInstance(DBProcess.class.getClassLoader(), new Class[]{DBProcess.class}, new Cache(new MySQL()));
@Override
public Integer createUser(User user) {
System.out.println("createUser in UserDaoImpl is invoked successfully..................");
proxy.insert(user);
return 1;
}
@Override
public Integer deleteUser(User user) {
System.out.println("deleteUser in UserDaoImpl is invoked successfully..................");
proxy.delete(user);
return 1;
}
@Override
public Integer updateUser(User user) {
System.out.println("updateUser in UserDaoImpl is invoked successfully..................");
proxy.update(user);
return 1;
}
@Override
public User retrieveUser(Long userId) {
System.out.println("retrieveUser in UserDaoImpl is invoked successfully..................");
return proxy.select(userId);
}
}
DBProcess.java
package com.ss.db;
import com.ss.entity.User;
public interface DBProcess {
Integer insert(User user);
Integer delete(User user);
Integer update(User user);
User select(Long userId);
}
Cache.java
package com.ss.db;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class Cache implements InvocationHandler{
//快取容器
private final static Map<Long, Object> cache = new HashMap<>();
private DBProcess db;
//只提供有參的構造器給外界,使得外界必須在獲取物件的同時初始化屬性
public Cache(DBProcess db) {
this.db = db;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1.BootStrapClassLoader 2.ExtClassLoader 3.AppClassLoader 4.自定義ClassLoader
if(method.getName().equalsIgnoreCase("select")){//如果時查詢方法則進行快取處理
if(cache.get(args[0])!=null) return cache.get(args[0]);///相同的引數則從快取中獲取
else{//如果快取中沒有則執行資料庫查詢並進行快取
Object obj = method.invoke(db, args);
cache.put((Long)args[0], obj);
return obj;
}
}else{
cache.clear();
Object obj = method.invoke(db, args);
return obj;
}
}
}
MySQL.java
package com.ss.db;
import java.util.Random;
import com.ss.entity.User;
public class MySQL implements DBProcess{
//兩個陣列自行初始化,長度一樣即可
private static String[] names = {};
private static String[] nickNames = {};
@Override
public Integer insert(User user) {
System.out.println(user + " is inserted to mysql successfullly............");
return 1;
}
@Override
public Integer delete(User user) {
System.out.println(user + " is deleted from mysql successfullly............");
return 1;
}
@Override
public Integer update(User user) {
System.out.println(user + " is updated to mysql successfullly............");
return 1;
}
@Override
public User select(Long userId) {
System.out.println("............ MySQL's select is invoked ...........");
Integer random = new Random().nextInt(10);
return new User(userId, names[random], nickNames[random]);
}
}
UserServiceImpl.java
package com.ss.service;
import org.junit.Test;
import com.ss.dao.UserDao;
import com.ss.dao.UserDaoImpl;
import com.ss.entity.User;
public class UserServiceImpl {
@Test
public void testCache(){
UserDao dao = new UserDaoImpl();
User user1 = dao.retrieveUser(12L);
User user2 = dao.retrieveUser(12L);
System.out.println(user1);
System.out.println(user1 == user2);
dao.deleteUser(new User(1L, "cache", "cc"));
User user3 = dao.retrieveUser(12L);
System.out.println(user3);
}
}
執行testCache方法,結果如下所示