分布式系统的一个重要问题就是分布式的事务,在没有分布式事务的前提下为了保证各个系统间数据的一致性比较简单易行的方法就是重试和补偿了。最近公司系统也遇到了这样的问题,远程调用超时或者消息消费失败之后造成了一些脏数据,为了给这些点统一加上重做机制首先就想到了Java的动态代理,如果稍微再能够灵活配置一点简单的做法就是加annotation。自己先写了一个简单的demo。
1。为了能够进行一些简单的配置化,定义了一个annotation。其中
- redoTimes:失败之后的重做次数。
- taskNameOnError:如果还是失败生成任务的名称。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface AutoRedo {
int redoTimes() default 1;
String taskNameOnError();
}
2。假如我们要动态代理的类和接口如下:(java本身的代理机制只支持接口的动态代理,如果要对类做动态代理可以使用cglib)。所以这个annotation一定要加在接口上,类上注解在代理上是不起作用的。
interface Subject {
@AutoRedo(redoTimes = 2, taskNameOnError = "xxRedoTask")
public void request();
}
class RealSubject implements Subject {
public void request() {
System.out.println("RealSubject request()!");
}
}
3。代理的时候要做的事情:
class DynamicProxy implements InvocationHandler {
private Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
int redoTimes = 0;
int failCnt = 0;
String taskNameOnError;
if (method.isAnnotationPresent(AutoRedo.class)) {
redoTimes = method.getAnnotation(AutoRedo.class).redoTimes();
taskNameOnError = method.getAnnotation(AutoRedo.class)
.taskNameOnError();
}
for (int i = 1; i <= redoTimes+1; i++) {
try {
method.invoke(this.obj, args);
break;
} catch (Exception e) {
failCnt++;
}
}
if (failCnt == redoTimes+1) {
// insert asynTask with name: taskNameOnError
}
return null;
}
}
4。最后写一个工厂来方便调用,因为java.lang.reflect.Proxy已经做了cache,保证同一个interface的proxy只动态生成一个。所以工厂就不做cache了,这样也不会出现持久带内存一直增长的问题。(无节制的生成动态class而产生的频发fullgc需要小心)
class RedoInterceptorFactory {
@SuppressWarnings("unchecked")
public static <T> T getInterceptedInstance(T target) {
InvocationHandler h = new DynamicProxy(target);
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), h);
}
}
5。真正的调用端
public static void main(String[] args) {
Subject realSubject = new RealSubject();
RedoInterceptorFactory.getInterceptedInstance(realSubject).request();
}
参考资料:
- http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/
- http://qa.taobao.com/?p=463
分享到:
相关推荐
java动态代理对象实现日志输出,另外再配上annotation实现注解输出。
Core.Java基础教程 13.高级编程-反射、动态代理与Annotation
JavaPoet+Annotation实现android动态权限申请 JavaPoet+Annotation实现android动态权限申请
java SSH项目 hibernate annotation
Java Annotation详解 Java Annotation详解 Java Annotation详解
Java 5 annotation 学习笔记Java 5 annotation 学习笔记Java 5 annotation 学习笔记
java之Annotation及其应用
Java annotation 什么是java annotation?annotation 的7种标注类型。nnotation提供了一条与程序元素关联任何信息或者任何元数据(metadata)的途径。从某些方面看,annotation就像修饰符一样被使用,并应用于包、...
java1.5 annotation注释源代码,
文档由五篇博客组成,说明了如何使用代理技术实现Annotation HttpClient通过,阅读这五篇博客,应该能够大致了解如何实现一个Annotation类型应用的框架。此外,配备了相应的Annotation HttpClient的源码,以供大家...
Java-Annotation使用大全 Java-Annotation使用大全 Java-Annotation使用大全
Java Annotation的讲解和例子~~~
个人收集的相关Java Annotation的资源资料内容。
本文针对java初学者或者annotation初次使用者全面地说明了annotation的使用方法、定义方式、分类。初学者可以通过以上的说明制作简单的annotation程序,但是对于一些高级的annotation应用(例如使用自定义annotation...
struts 拦截器,扩展,以及java annotation 这个是我学习所用,放在此处,作为中转。
JAVA注解(Annotation).doc JAVA注解(Annotation).doc
java annotation手册 关于annotation是什么东西,百度一下会有很多关于它的描述,在这里就不用再copy了,我们还是以一个示例开始吧,在开始示例之前,我们先来一个小故事。
从某些方面看,annotation就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在annotation的“name=value”结构对中。annotation类型是一种接口,能够通过...
网上的Java并发编程源码一般都缺失一些Annotation,导致导入会报错。
JAVA Annotation学习示例 的一个简单示例 有源码 也有相关博客说明