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方法,结果如下所示

猜你喜欢

转载自blog.csdn.net/m0_37561039/article/details/84026657
今日推荐