编码素养5:减少冗余代码-让一段方法Template-callback
来源:互联网 发布:淘宝网男装新款 编辑:程序博客网 时间:2024/05/01 08:16
有3个方法,签名完全不同,但执行时都可能发生异常。要求:无论哪个方法异常,都需要重试3次。假设重试3次的逻辑很复杂,但3个方法的逻辑都是相同的。如何复用重试代码?
public class FFMPEGManagerRedo implements FFMPEGManager { private static final Logger LOG = LoggerFactory.getLogger(FFMPEGManagerRedo.class); /** 重试的次数和间隔 */ private int[] retryInterval; private FFMPEGManager ffmpegManager; public FFMPEGManagerRedo(FFMPEGManager ffmpegManager, int[] retryInterval) { super(); if (retryInterval == null || retryInterval.length == 0) { throw new IllegalArgumentException("retry times should be greater than 0"); } this.ffmpegManager = ffmpegManager; this.retryInterval = retryInterval; } public FFMPEGManagerRedo(FFMPEGManager ffmpegManager) { this(ffmpegManager, new int[] { 1, 2, 4 });//指数递增 } @Override public MetaInfo readMetaInfo(String videoFileName) throws Exception { try { return ffmpegManager.readMetaInfo(videoFileName);//重试的时候才反射(减少反射对性能影响) } catch (Exception e) { Class<?>[] argsType = new Class<?>[] { String.class }; Object[] argsValue = new Object[] { videoFileName }; return (MetaInfo) retryMethod(ffmpegManager.getClass().getMethod("readMetaInfo", argsType), ffmpegManager, argsValue); } } @Override public void extractThumb(String videoFileName, ThumbSpec thumbSpec, String thumbFileName) throws Exception { try { ffmpegManager.extractThumb(videoFileName, thumbSpec, thumbFileName);//重试的时候才反射(减少反射对性能影响) } catch (Exception e) { Class<?>[] argsType = new Class<?>[] { String.class, ThumbSpec.class, String.class }; Object[] argsValue = new Object[] { videoFileName, thumbSpec, thumbFileName }; retryMethod(ffmpegManager.getClass().getMethod("extractThumb", argsType), ffmpegManager, argsValue); } } @Override public void transcode(String videoFileName, TranscodeSpec transcodeSpec, String transcodeFileName) throws Exception { try { ffmpegManager.transcode(videoFileName, transcodeSpec, transcodeFileName);//重试的时候才反射(减少反射对性能影响) } catch (Exception e) { Class<?>[] argsType = new Class<?>[] { String.class, TranscodeSpec.class, String.class }; Object[] argsValue = new Object[] { videoFileName, transcodeSpec, transcodeFileName }; retryMethod(ffmpegManager.getClass().getMethod("transcode", argsType), ffmpegManager, argsValue); } } /* Retry Template-Callback */ protected Object retryMethod(Method method, Object instance, Object... args) throws Exception { int retryCnt = 1; Exception lastException = null; do { try { Object r = method.invoke(instance, args);//method callback LOG.info("method {} invoke retry succ at time {}", method.getName(), retryCnt); return r; } catch (java.lang.reflect.InvocationTargetException targetException) { Throwable targetThrowable = targetException.getTargetException(); if (targetException instanceof Exception) {//TargetException会被转译 lastException = (Exception) targetThrowable; } else { lastException = targetException; } } catch (Exception e) { lastException = e; } if (lastException != null) { LOG.warn("method {} invoke fail at time {}, retry ...", method.getName(), retryCnt, lastException); if (retryCnt < retryInterval.length) {//最后一次不用睡眠 Thread.sleep(1000L * retryInterval[retryCnt]);//retry interval } retryCnt++; } } while (retryCnt < retryInterval.length); throw lastException; }}
TestCase:
public class FFMPEGManagerRedoTest { private static final Logger LOG = LoggerFactory.getLogger(FFMPEGManagerRedoTest.class); //非public时,反射获取不到 public static class CountedFFMPEGManager implements FFMPEGManager { private int metaCnt = 0; private int thumbCnt = 0; private int transCnt = 0; private int maxFailCnt = 3; public CountedFFMPEGManager(int maxFailCnt) { super(); this.maxFailCnt = maxFailCnt; } @Override public MetaInfo readMetaInfo(String videoFileName) throws Exception { metaCnt++; if (metaCnt < maxFailCnt) { throw new Exception("mock fail"); } MetaInfo meta = new MetaInfo(); meta.setSizeByte(1024); return meta; } @Override public void extractThumb(String videoFileName, ThumbSpec thumbSpec, String thumbFileName) throws Exception { thumbCnt++; if (thumbCnt < maxFailCnt) { throw new Exception("mock fail"); } } @Override public void transcode(String videoFileName, TranscodeSpec transcodeSpec, String transcodeFileName) throws Exception { transCnt++; if (transCnt < maxFailCnt) { throw new Exception("mock fail"); } } public int getMetaCnt() { return metaCnt; } public int getThumbCnt() { return thumbCnt; } public int getTransCnt() { return transCnt; } } private CountedFFMPEGManager counted; private FFMPEGManagerRedo redo; @Before public void setUp() throws Exception { counted = new CountedFFMPEGManager(3);//最多允许失败3次 redo = new FFMPEGManagerRedo(counted, new int[] { 1, 2, 4 });//如果失败,还可以重试3次 } @Test public void testMeta() throws Exception { MetaInfo meta = redo.readMetaInfo("videoFileName"); LOG.info("meta cnt: {}", counted.getMetaCnt()); Assert.assertEquals(3, counted.getMetaCnt()); Assert.assertNotNull(meta); Assert.assertEquals(1024, meta.getSizeByte()); } @Test public void testThrumb() throws Exception { ThumbSpec thumbSpec = new ThumbSpec(120, 90, 2); redo.extractThumb("videoFileName.mp4", thumbSpec, "thumbFileName.jpg"); LOG.info("thumb cnt: {}", counted.getThumbCnt()); Assert.assertEquals(3, counted.getThumbCnt()); } @Test public void testTrans() throws Exception { TranscodeSpec transcodeSpec = new TranscodeSpec(); redo.transcode("videoFileName.flv", transcodeSpec, "transcodeFileName.mp4"); LOG.info("trans cnt: {}", counted.getTransCnt()); Assert.assertEquals(3, counted.getTransCnt()); } @Test public void testBeyondRetryTimes() { redo = new FFMPEGManagerRedo(counted, new int[] { 1 });//只重试1次,Mock会连续失败3次,最终结果是失败 Exception exception = null; MetaInfo meta = null; try { meta = redo.readMetaInfo("videoFileName"); } catch (Exception e) { exception = e; System.err.println(e); } Assert.assertNull(meta); Assert.assertNotNull(exception); Assert.assertEquals("mock fail", exception.getMessage()); }}
0 0
- 编码素养5:减少冗余代码-让一段方法Template-callback
- 用 Groovy 减少代码冗余
- c#编译器的减少冗余代码优化
- Java Lombok 减少代码冗余 利刃
- 使用APT减少MVP的冗余代码
- Android Studio常用代码模版,让编码飞起来 template
- C++编码优化之减少冗余拷贝或赋值
- template-callback
- 程序如何做到代码复用,减少代码冗余,从而减少代码修改的成本?
- 在webxml中进行数据库参数配置,减少代码冗余
- 【机房重构】——减少代码冗余
- 减少代码嵌套的方法
- 一段代码让你秒懂java方法到底是传值还是传地址
- 减少冗余的小技巧
- [java]让人尴尬的一段代码
- java之Unicode编码 -一段代码
- 类设计要点: 变量/函数的命名要泛化,减少代码”冗余“
- UI组件设计:减少冗余代码--类继承关系的考量
- maven命令大全
- HDU 4856 Tunnels (最短路+状压DP)
- Microsoft SQL Server数据库恢复中断,如何删除失败的数据库以便以后再次恢复
- 学习笔记---网络编程
- static修饰的类属性
- 编码素养5:减少冗余代码-让一段方法Template-callback
- ZOJ-1195
- bzoj1854 [Scoi2010]游戏
- 使用CoreText实现的一个富文本显示组件
- jsp、el、jstl——前端面试
- java8 - 方法引用(method referrance)
- HDU2955概率背包
- 华为测试 超长整数相加
- UVA 10010 (暑假-字符串(2) -A - Where's Waldorf?)