1.为什么要用Redis代理
答:在项目中,我们一般使用Redis来做缓存,根据公司要求,需要对使用的各自场景进行日志上报,一方面是为了排查及定位问题,另一方面,为报表提供原始数据。上面说的会涉及两个功能,一个是trace日志打印,及metric上报,那我们怎么在Redis一次访问,实现这两种功能呢,可以考虑代理。
2. Redis代理怎么实现Trace日志打印及Metric上报?
2.1 既然是代理,那么必然是代理一个接口,那我们代理哪个接口?
答:JedisCommond
public class RedisProxy implements InvocationHandler {
RedisProxy(JedisPool jedisPool, LinkedList<InvocationInterceptor> interceptors) {
this.jedisPool = jedisPool;
this.interceptors = interceptors;
}
public JedisCommands getInstance() {
if (null == this.instance) {
synchronized(this) {
if (null == this.instance) {
JedisCommands proxy = (JedisCommands)Proxy.newProxyInstance(Jedis.class.getClassLoader(), Jedis.class.getInterfaces(), this);
this.instance = new SimpleJedisCommands(proxy);
}
}
}
return this.instance;
}
}
2.2 两个功能的拦截器,在构建RedisProxy参数的时候,将两个拦截器初始化
MetricInterceptor TraceLogInterceptor
他们实现了InvocationInterceptor
public interface InvocationInterceptor {
boolean preHandle(InvocationContext var1);
Object postHandle(InvocationContext var1);
void afterCompletion(InvocationContext var1);
}
2.3 如何执行?
public Object invoke(Object proxy, Method method, Object[] args) {
InvocationContext context = this.buildContext(proxy, method, client, args);
try {
while(listIterator.hasNext()) {
InvocationInterceptor current = (InvocationInterceptor)listIterator.next();
if (!current.preHandle(context)) {
}
}
result = method.invoke(client, args);
context.setResult(result);
while(listIterator.hasPrevious()) {
result = ((InvocationInterceptor)listIterator.previous()).postHandle(context);
context.setResult(result);
}....
}