设计模式之抽象工厂模式:「替换多种缓存,代理抽象场景」
in 002-设计模式 with 2 comment

设计模式之抽象工厂模式:「替换多种缓存,代理抽象场景」

in 002-设计模式 with 2 comment

1. 前言

很多时候初期业务的蛮荒发展,也会牵动着研发对系统的建设。

预估QPS较低、系统压力较小、并发访问不大、近一年没有大动作等等,在考虑时间投入成本的前提前,并不会投入特别多的人力去构建非常完善的系统。就像对缓存的使用,往往可能只要是一种缓存即可满足现状。

但随着业务超过预期的快速发展,系统的负载能力也要随着跟上。原有的缓存已经满足不了系统需求。这时候就需要更换为更为健壮的缓存服务,比如本地缓存,redis缓存共同使用,多种选择缓存,虽然需要修改但是不能影响目前系统的运行,还要平滑过渡过去。

随着这次的升级,可以预见的问题会有:

2. 现状

public interface CacheProviderService {

    /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @return T
     * @author zhouxinlei
     * @date 2020-01-27 20:19:27
     */
    <T> T get(String key);

    /**
     * 查询缓存
     *
     * @param key      缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @return T
     */
    <T> T get(String key, Function<String, T> function);

    /**
     * 查询缓存
     *
     * @param key       缓存键 不可为空
     * @param function  如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParam function函数的调用参数
     * @return T
     */
    <T, M> T get(String key, Function<M, T> function, M funcParam);

    /**
     * 查询缓存
     *
     * @param key        缓存键 不可为空
     * @param function   如没有缓存,调用该callable函数返回对象 可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     * @return T
     **/
    <T> T get(String key, Function<String, T> function, Long expireTime);

    /**
     * 查询缓存
     *
     * @param key        缓存键 不可为空
     * @param function   如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParam  function函数的调用参数
     * @param expireTime 过期时间(单位:毫秒) 可为空
     * @return T
     **/
    <T, M> T get(String key, Function<M, T> function, M funcParam, Long expireTime);

    /**
     * 设置缓存键值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     * @return void
     **/
    <T> void set(String key, T obj);

    /**
     * 设置缓存键值
     *
     * @param key        缓存键 不可为空
     * @param obj        缓存值 不可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     * @return void
     **/
    <T> void set(String key, T obj, Long expireTime);

    /**
     * 自增长
     *
     * @param key   key值
     * @param delta 自增间距
     * @return Long
     */
    Long increment(String key, long delta);

    /**
     * 自减
     *
     * @param key   key值
     * @param delta 自减间距
     * @return Long
     * @author zhouxinlei
     * @date 2019-10-11 16:23:58
     */
    Long decrement(String key, long delta);

    /**
     * 移除缓存
     *
     * @param key 缓存键 不可为空
     * @return void
     **/
    void remove(String key);

    /**
     * 是否存在缓存
     *
     * @param key 缓存键 不可为空
     * @return boolean
     **/
    boolean contains(String key);

}
@Component
@Slf4j
public class CacheProviderImpl implements CacheProviderService {

    private final RedisTemplate<String, Object> redisTemplate;

    private ValueOperations<String, Object> valueOperations;

    private final static long CACHE_MINUTE = 60;

    public CacheProviderImpl(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @PostConstruct
    public void initRedisOperation() {
        valueOperations = redisTemplate.opsForValue();
    }

    @Override
    public <T> T get(String key) {
        return get(key, null, null, CACHE_MINUTE);
    }

    @Override
    public <T> T get(String key, Function<String, T> function) {
        return get(key, function, key, CACHE_MINUTE);
    }

    @Override
    public <T, M> T get(String key, Function<M, T> function, M funcParam) {
        return get(key, function, funcParam, CACHE_MINUTE);
    }

    @Override
    public <T> T get(String key, Function<String, T> function, Long expireTime) {
        return get(key, function, key, expireTime);
    }

    @Override
    public <T, M> T get(String key, Function<M, T> function, M funcParm, Long expireTime) {
        T obj = null;
        if (StringUtils.isEmpty(key)) {
            return null;
        }
        expireTime = getExpireTime(expireTime);
        try {
            obj = (T) valueOperations.get(key);
            if (function != null && obj == null) {
                obj = function.apply(funcParm);
                if (obj != null) {
                    //设置缓存信息
                    set(key, obj, expireTime);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return obj;
    }

    @Override
    public <T> void set(String key, T obj) {
        set(key, obj, CACHE_MINUTE);
    }

    @Override
    public <T> void set(String key, T obj, Long expireTime) {
        if (StringUtils.isEmpty(key)) {
            return;
        }
        if (obj == null) {
            return;
        }
        valueOperations.set(key, obj,expireTime,TimeUnit.SECONDS);
    }

    @Override
    public Long increment(String key, long delta) {
        return valueOperations.increment(key, delta);
    }

    @Override
    public Long decrement(String key, long delta) {
        return valueOperations.decrement(key, delta);
    }

    @Override
    public void remove(String key) {
        if (StringUtils.isEmpty(key)) {
            return;
        }
        redisTemplate.delete(key);
    }

    @Override
    public boolean contains(String key) {
        boolean exists = false;
        if (StringUtils.isEmpty(key)) {
            return false;
        }
        Object obj = get(key);
        if (obj != null) {
            exists = true;
        }
        return exists;
    }

    /**
     * 获取过期时间 单位:毫秒
     *
     * @param expireTime 传人的过期时间 单位毫秒 如小于1分钟,默认为10分钟
     **/
    private Long getExpireTime(Long expireTime) {
        Long result = expireTime;
        if (expireTime == null || expireTime < CACHE_MINUTE) {
            result = CACHE_MINUTE;
        }
        return result;
    }

}

3. 实现

思路,我这边想到两种实现思路,一种通过spring注解Qualifier实现,另一种通过抽象工厂模式+适配器模式+JDK动态代理模式来实现

设计模式对比

3.1 Qualifier方式

这边新加GuavaCache本地缓存,实现CacheProviderService
接口,这样CacheProviderService有两个实现类,通过

@Qualifier("redisCacheProviderImpl")
private CacheProviderService cacheProviderService;

注入使用,指定bean选择合适的实现业务缓存

3.2 抽象工厂模式+适配器模式+JDK动态代理模式实现

3.2.1 简介实现

image.png

涉及的部分核心功能代码

3.2.2 代码实现

import java.util.function.Function;

/**
 * description:
 *
 * @author: zhouxinlei
 * @date: 2020-07-08 10:01:32
 */
public interface ICacheAdapter {

    /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @return T
     * @author zhouxinlei
     * @date 2020-01-27 20:19:27
     */
    <T> T get(String key);

    /**
     * 查询缓存
     *
     * @param key      缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @return T
     */
    <T> T get(String key, Function<String, T> function);

    /**
     * 查询缓存
     *
     * @param key       缓存键 不可为空
     * @param function  如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParam function函数的调用参数
     * @return T
     */
    <T, M> T get(String key, Function<M, T> function, M funcParam);

    /**
     * 查询缓存
     *
     * @param key        缓存键 不可为空
     * @param function   如没有缓存,调用该callable函数返回对象 可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     * @return T
     **/
    <T> T get(String key, Function<String, T> function, Long expireTime);

    /**
     * 查询缓存
     *
     * @param key        缓存键 不可为空
     * @param function   如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParam  function函数的调用参数
     * @param expireTime 过期时间(单位:毫秒) 可为空
     * @return T
     **/
    <T, M> T get(String key, Function<M, T> function, M funcParam, Long expireTime);

    /**
     * 设置缓存键值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     * @return void
     **/
    <T> void set(String key, T obj);

    /**
     * 设置缓存键值
     *
     * @param key        缓存键 不可为空
     * @param obj        缓存值 不可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     * @return void
     **/
    <T> void set(String key, T obj, Long expireTime);

    /**
     * 自增长
     *
     * @param key   key值
     * @param delta 自增间距
     * @return Long
     */
    Long increment(String key, long delta);

    /**
     * 自减
     *
     * @param key   key值
     * @param delta 自减间距
     * @return Long
     * @author zhouxinlei
     * @date 2019-10-11 16:23:58
     */
    Long decrement(String key, long delta);

    /**
     * 移除缓存
     *
     * @param key 缓存键 不可为空
     * @return void
     **/
    void remove(String key);

    /**
     * 是否存在缓存
     *
     * @param key 缓存键 不可为空
     * @return boolean
     **/
    boolean contains(String key);

}
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;
import com.sparksys.commons.core.cache.ICacheAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * description:Guava Cache
 *
 * @author zhouxinlei
 * @date 2020/6/17 0017
 */
@Slf4j
@Component
public class GuavaCacheAdapter implements ICacheAdapter {

    private static final Map<String, Cache<String, Object>> CACHE_CONCURRENT_MAP = Maps.newConcurrentMap();

    private static final long CACHE_MAXIMUM_SIZE = 100;

    private static final long CACHE_MINUTE = 10 * 60;

    private static final Lock LOCK = new ReentrantLock();

    static {
        Cache<String, Object> cacheContainer = CacheBuilder.newBuilder()
                .maximumSize(CACHE_MAXIMUM_SIZE)
                //最后一次写入后的一段时间移出
                .expireAfterWrite(CACHE_MINUTE, TimeUnit.SECONDS)
                //.expireAfterAccess(CACHE_MINUTE, TimeUnit.MILLISECONDS) //最后一次访问后的一段时间移出
                .recordStats()//开启统计功能
                .build();
        CACHE_CONCURRENT_MAP.put(String.valueOf(CACHE_MINUTE), cacheContainer);
    }

    /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     **/
    @Override
    public <T> T get(String key) {
        return get(key, null, null, CACHE_MINUTE);
    }

    /**
     * 查询缓存
     *
     * @param key      缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     **/
    @Override
    public <T> T get(String key, Function<String, T> function) {
        return get(key, function, key, CACHE_MINUTE);
    }

    /**
     * 查询缓存
     *
     * @param key       缓存键 不可为空
     * @param function  如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParam function函数的调用参数
     **/
    @Override
    public <T, M> T get(String key, Function<M, T> function, M funcParam) {
        return get(key, function, funcParam, CACHE_MINUTE);
    }

    /**
     * 查询缓存
     *
     * @param key        缓存键 不可为空
     * @param function   如没有缓存,调用该callable函数返回对象 可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
    @Override
    public <T> T get(String key, Function<String, T> function, Long expireTime) {
        return get(key, function, key, expireTime);
    }

    /**
     * 查询缓存
     *
     * @param key        缓存键 不可为空
     * @param function   如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParam  function函数的调用参数
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
    @Override
    public <T, M> T get(String key, Function<M, T> function, M funcParam, Long expireTime) {
        T obj = null;
        if (StringUtils.isEmpty(key)) {
            return null;
        }
        expireTime = getExpireTime(expireTime);
        Cache<String, Object> cacheContainer = getCacheContainer(expireTime);
        try {
            if (function == null) {
                obj = (T) cacheContainer.getIfPresent(key);
            } else {
                obj = (T) cacheContainer.get(key, () -> function.apply(funcParam));
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return obj;
    }

    /**
     * 设置缓存键值  直接向缓存中插入值,这会直接覆盖掉给定键之前映射的值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     **/
    @Override
    public <T> void set(String key, T obj) {
        set(key, obj, CACHE_MINUTE);
    }

    /**
     * 设置缓存键值  直接向缓存中插入值,这会直接覆盖掉给定键之前映射的值
     *
     * @param key        缓存键 不可为空
     * @param obj        缓存值 不可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
    @Override
    public <T> void set(String key, T obj, Long expireTime) {
        if (StringUtils.isEmpty(key)) {
            return;
        }
        if (obj == null) {
            return;
        }
        expireTime = getExpireTime(expireTime);
        Cache<String, Object> cacheContainer = getCacheContainer(expireTime);
        cacheContainer.put(key, obj);
    }

    @Override
    public Long increment(String key, long delta) {
        Long expireTime = getExpireTime(CACHE_MINUTE);
        Cache<String, Object> cacheContainer = getCacheContainer(expireTime);
        Supplier<LongAdder> function = LongAdder::new;
        LongAdder longAdder;
        try {
            longAdder = (LongAdder) cacheContainer.get(key, function::get);
            longAdder.add(delta);
            cacheContainer.put(key, longAdder);
            return longAdder.longValue();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return 0L;
    }

    @Override
    public Long decrement(String key, long delta) {
        Long expireTime = getExpireTime(CACHE_MINUTE);
        Cache<String, Object> cacheContainer = getCacheContainer(expireTime);
        Supplier<LongAdder> function = LongAdder::new;
        LongAdder longAdder;
        try {
            longAdder = (LongAdder) cacheContainer.get(key, function::get);
            longAdder.add(-delta);
            cacheContainer.put(key, longAdder);
            return longAdder.longValue();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return 0L;
    }

    /**
     * 移除缓存
     *
     * @param key 缓存键 不可为空
     **/
    @Override
    public void remove(String key) {
        if (StringUtils.isEmpty(key)) {
            return;
        }
        long expireTime = getExpireTime(CACHE_MINUTE);
        Cache<String, Object> cacheContainer = getCacheContainer(expireTime);
        cacheContainer.invalidate(key);
    }

    /**
     * 是否存在缓存
     *
     * @param key 缓存键 不可为空
     **/
    @Override
    public boolean contains(String key) {
        boolean exists = false;
        if (StringUtils.isEmpty(key)) {
            return false;
        }
        Object obj = get(key);
        if (obj != null) {
            exists = true;
        }
        return exists;
    }

    private Cache<String, Object> getCacheContainer(Long expireTime) {
        Cache<String, Object> cacheContainer;
        if (expireTime == null) {
            return null;
        }
        String mapKey = String.valueOf(expireTime);
        if (CACHE_CONCURRENT_MAP.containsKey(mapKey)) {
            cacheContainer = CACHE_CONCURRENT_MAP.get(mapKey);
            return cacheContainer;
        }
        LOCK.lock();
        try {
            cacheContainer = CacheBuilder.newBuilder()
                    .maximumSize(CACHE_MAXIMUM_SIZE)
                    //最后一次写入后的一段时间移出
                    .expireAfterWrite(expireTime, TimeUnit.SECONDS)
                    //.expireAfterAccess(AppConst.CACHE_MINUTE, TimeUnit.MILLISECONDS) //最后一次访问后的一段时间移出
                    .recordStats()//开启统计功能
                    .build();
            CACHE_CONCURRENT_MAP.put(mapKey, cacheContainer);
        } finally {
            LOCK.unlock();
        }
        return cacheContainer;
    }

    /**
     * 获取过期时间 单位:秒
     *
     * @param expireTime 传人的过期时间 单位秒 如小于1分钟,默认为10分钟
     **/
    private Long getExpireTime(Long expireTime) {
        Long result = expireTime;
        if (expireTime == null || expireTime < CACHE_MINUTE / 10) {
            result = CACHE_MINUTE;
        }
        return result;
    }
}
import com.sparksys.commons.core.cache.ICacheAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * description: redis缓存实现
 *
 * @author zhouxinlei
 * @date 2020-05-24 13:28:55
 */
@Component
@Slf4j
public class RedisCacheAdapter implements ICacheAdapter {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private ValueOperations<String, Object> valueOperations;

    private final static long CACHE_MINUTE = 60;

    @PostConstruct
    public void initRedisOperation() {
        valueOperations = redisTemplate.opsForValue();
    }

    @Override
    public <T> T get(String key) {
        return get(key, null, null, CACHE_MINUTE);
    }

    @Override
    public <T> T get(String key, Function<String, T> function) {
        return get(key, function, key, CACHE_MINUTE);
    }

    @Override
    public <T, M> T get(String key, Function<M, T> function, M funcParam) {
        return get(key, function, funcParam, CACHE_MINUTE);
    }

    @Override
    public <T> T get(String key, Function<String, T> function, Long expireTime) {
        return get(key, function, key, expireTime);
    }

    @Override
    public <T, M> T get(String key, Function<M, T> function, M funcParm, Long expireTime) {
        T obj = null;
        if (StringUtils.isEmpty(key)) {
            return null;
        }
        expireTime = getExpireTime(expireTime);
        try {
            obj = (T) valueOperations.get(key);
            if (function != null && obj == null) {
                obj = function.apply(funcParm);
                if (obj != null) {
                    //设置缓存信息
                    set(key, obj, expireTime);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return obj;
    }

    @Override
    public <T> void set(String key, T obj) {
        set(key, obj, CACHE_MINUTE);
    }

    @Override
    public <T> void set(String key, T obj, Long expireTime) {
        if (StringUtils.isEmpty(key)) {
            return;
        }
        if (obj == null) {
            return;
        }
        expireTime = getExpireTime(expireTime);
        valueOperations.set(key, obj, expireTime, TimeUnit.SECONDS);
    }

    @Override
    public Long increment(String key, long delta) {
        return valueOperations.increment(key, delta);
    }

    @Override
    public Long decrement(String key, long delta) {
        return valueOperations.decrement(key, delta);
    }

    @Override
    public void remove(String key) {
        if (StringUtils.isEmpty(key)) {
            return;
        }
        redisTemplate.delete(key);
    }

    @Override
    public boolean contains(String key) {
        boolean exists = false;
        if (StringUtils.isEmpty(key)) {
            return false;
        }
        Object obj = get(key);
        if (obj != null) {
            exists = true;
        }
        return exists;
    }

    /**
     * 获取过期时间 单位:毫秒
     *
     * @param expireTime 传人的过期时间 单位毫秒 如小于1分钟,默认为10分钟
     **/
    private Long getExpireTime(Long expireTime) {
        Long result = expireTime;
        if (expireTime == null || expireTime < CACHE_MINUTE) {
            result = CACHE_MINUTE;
        }
        return result;
    }
}
import cn.hutool.core.util.ClassLoaderUtil;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * description: 类加载工具类
 *
 * @author: zhouxinlei
 * @date: 2020-07-08 11:22:32
 */
public class ClassLoaderUtils extends ClassLoaderUtil {

    private static final Set<Class> PRIMITIVE_SET = new HashSet<>();

    static {
        PRIMITIVE_SET.add(Integer.class);
        PRIMITIVE_SET.add(Long.class);
        PRIMITIVE_SET.add(Float.class);
        PRIMITIVE_SET.add(Byte.class);
        PRIMITIVE_SET.add(Short.class);
        PRIMITIVE_SET.add(Double.class);
        PRIMITIVE_SET.add(Character.class);
        PRIMITIVE_SET.add(Boolean.class);
    }

    /**
     * 实例化一个对象(只检测默认构造函数,其它不管)
     *
     * @param clazz 对象类
     * @param <T>   对象具体类
     * @return 对象实例
     * @throws Exception 没有找到方法,或者无法处理,或者初始化方法异常等
     */
    public static <T> T newInstance(Class<T> clazz) throws Exception {
        if (PRIMITIVE_SET.contains(clazz)) {
            return null;
        }
        if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
            Constructor[] constructorList = clazz.getDeclaredConstructors();
            Constructor defaultConstructor = null;
            for (Constructor con : constructorList) {
                if (con.getParameterTypes().length == 1) {
                    defaultConstructor = con;
                    break;
                }
            }
            if (defaultConstructor != null) {
                if (defaultConstructor.isAccessible()) {
                    return (T) defaultConstructor.newInstance(new Object[]{null});
                } else {
                    try {
                        defaultConstructor.setAccessible(true);
                        return (T) defaultConstructor.newInstance(new Object[]{null});
                    } finally {
                        defaultConstructor.setAccessible(false);
                    }
                }
            } else {
                throw new Exception("The " + clazz.getCanonicalName() + " has no default constructor!");
            }
        }
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            Constructor<T> constructor = clazz.getDeclaredConstructor();
            if (constructor.isAccessible()) {
                throw new Exception("The " + clazz.getCanonicalName() + " has no default constructor!", e);
            } else {
                try {
                    constructor.setAccessible(true);
                    return constructor.newInstance();
                } finally {
                    constructor.setAccessible(false);
                }
            }
        }
    }

    public static Class<?>[] getClazzByArgs(Object[] args) {
        Class<?>[] parameterTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ArrayList) {
                parameterTypes[i] = List.class;
                continue;
            }
            if (args[i] instanceof LinkedList) {
                parameterTypes[i] = List.class;
                continue;
            }
            if (args[i] instanceof HashMap) {
                parameterTypes[i] = Map.class;
                continue;
            }
            if (args[i] instanceof Long) {
                parameterTypes[i] = long.class;
                continue;
            }
            if (args[i] instanceof Double) {
                parameterTypes[i] = double.class;
                continue;
            }
            if (args[i] instanceof TimeUnit) {
                parameterTypes[i] = TimeUnit.class;
                continue;
            }
            parameterTypes[i] = args[i].getClass();
        }
        return parameterTypes;
    }

    public Method getMethod(Class<?> classType, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
        return classType.getMethod(methodName, parameterTypes);
    }

}
import com.sparksys.commons.core.utils.ClassLoaderUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * description: JDK动态代理实现类
 *
 * @author: zhouxinlei
 * @date: 2020-07-08 10:09:45
 */
public class JdkInvocationHandler implements InvocationHandler {

    private final ICacheAdapter cacheAdapter;

    public JdkInvocationHandler(ICacheAdapter cacheAdapter) {
        this.cacheAdapter = cacheAdapter;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return ICacheAdapter.class.getMethod(method.getName(), ClassLoaderUtils.getClazzByArgs(args)).invoke(cacheAdapter,
                args);
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * description:
 *
 * @author: zhouxinlei
 * @date: 2020-07-08 10:12:12
 */
public class JdkCacheProxy {

    public static <T> T getProxy(Class<T> interfaceClass, ICacheAdapter cacheAdapter) {
        InvocationHandler invocationHandler = new JdkInvocationHandler(cacheAdapter);
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Class<?>[] classes = interfaceClass.getInterfaces();
        //noinspection unchecked
        return (T) Proxy.newProxyInstance(classLoader, new Class[]{classes[0]}, invocationHandler);
    }
}

4 总结