├── .gitignore ├── LICENSE.txt ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── alibaba │ │ └── asyncload │ │ ├── AsyncLoadConfig.java │ │ ├── AsyncLoadExecutor.java │ │ ├── AsyncLoadMethodMatch.java │ │ ├── AsyncLoadProxy.java │ │ └── impl │ │ ├── AsyncLoadEnhanceProxy.java │ │ ├── AsyncLoadObject.java │ │ ├── AsyncLoadPerl5RegexpMethodMatcher.java │ │ ├── AsyncLoadResult.java │ │ ├── AsyncLoadService.java │ │ ├── AsyncLoadStatus.java │ │ ├── exceptions │ │ └── AsyncLoadException.java │ │ ├── helper │ │ ├── AsyncLoadProxyRepository.java │ │ └── AsyncLoadReflectionHelper.java │ │ ├── pool │ │ ├── AsyncLoadCallable.java │ │ ├── AsyncLoadFuture.java │ │ ├── AsyncLoadThreadPool.java │ │ └── NamedThreadFactory.java │ │ ├── spring │ │ ├── AsyncLoadFactoryBean.java │ │ ├── AsyncLoadInterceptor.java │ │ └── CompositeAutoProxyCreator.java │ │ ├── template │ │ ├── AsyncLoadCallback.java │ │ └── AsyncLoadTemplate.java │ │ └── util │ │ ├── AsyncLoadBarrier.java │ │ └── AsyncLoadUtils.java └── resources │ └── bean-asyncload-sample.xml └── test ├── java └── com │ └── alibaba │ └── asyncload │ ├── AsyncLoadExecutorTest.java │ ├── AsyncLoadFinalClassTest.java │ ├── AsyncLoadMethodMatchTest.java │ ├── AsyncLoadProxyTest.java │ ├── AsyncLoadReturnClassTest.java │ ├── AsyncLoadThreadLocalTest.java │ ├── BaseAsyncLoadNoRunTest.java │ ├── TestUtils.java │ ├── classinfo │ ├── AsyncLoadClassinfoTest.java │ ├── ClassInfoService.java │ └── JavassistClassinfoTest.java │ ├── domain │ ├── AsyncLoadTestModel.java │ ├── AsyncLoadTestService.java │ ├── AsyncLoadTestServiceDAO.java │ └── AsyncLoadTestServiceImpl.java │ ├── helper │ └── AsyncLoadReflectionHelperTest.java │ ├── spring │ ├── AsyncLoadFactoryBeanTest.java │ ├── AsyncLoadSpringCompsiteTest.java │ ├── AsyncLoadSpringInteceptorTest.java │ └── LogInteceptor.java │ ├── template │ └── AsyncLoadTemplateTest.java │ └── util │ ├── AsyncLoadBarrierTest.java │ └── AsyncLoadUtilsTest.java └── resources └── asyncload └── applicationContext.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .svn/ 2 | target/ 3 | test-output/ 4 | *.class 5 | .classpath 6 | .project 7 | .settings/ 8 | tmp 9 | temp 10 | *.log 11 | .idea/ 12 | *.iml 13 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

背景

2 | 3 |

前段时间在做应用的性能优化时,分析了下整体请求,profile看到90%的时间更多的是一些外部服务的I/O等待,cpu利用率其实不高,在10%以下。 单次请求的响应时间在50ms左右,所以tps也不会太高,测试环境压力测试过程,受限于环境因素撑死只能到200tps,20并发下。

4 | 5 |

6 |

I/O

7 |
目前一般的I/O的访问速度: L1 > L2 > memory -> disk or network
8 |
9 |
常见的IO:
10 | 11 |
    12 |
  1. nas上文件 (共享文件存储)
  2. 13 |
  3. output/xxx (磁盘文件)
  4. 14 |
  5. memcache client / cat client (cache服务)
  6. 15 |
  7. database (oracle , mysql) (数据库)
  8. 16 |
  9. dubbo client (外部服务)
  10. 17 |
  11. search client (搜索引擎)
  12. 18 |
19 | 20 |

思路

21 | 22 |

23 |

正因为考虑到I/O阻塞,长的外部环境单个请求处理基本都是在几十ms,最终的出路只能异步+并行,从而诞生了该开源产品

24 | 25 |

项目介绍

26 |

名称:asyncload

27 |

译意: async cocurrent load

28 |

语言: 纯java开发

29 |

定位: 业务层异步并行加载工具包,减少页面响应时间

30 |

31 | 32 |

工作原理

33 |


34 |

原理描述:

35 |

1. 针对方法调用,基于字节码增强技术,运行时生成代理类,快速返回mock对象,后台异步进行调用

36 |

2. 通过管理和调度线程池,将后台异步调用进行加速处理,达到一个平衡点

37 |

3. 业务执行过程需要获取mock对象的真实数据时,阻塞等待原始结果返回,整个过程透明完成

38 | 39 |

很明显,经过异步并行加载后,一次request请求总的响应时间就等于最长的依赖关系请求链的相应时间。

40 | 41 |

相关文档

42 | 43 | See the wiki page for : wiki文档 44 | 45 |
46 | wiki文档列表 47 | 54 | 55 |

56 |

问题反馈

57 |

1. qq交流群: 161559791

58 |

2. 邮件交流: jianghang115@gmail.com

59 |

3. 新浪微博: agapple0002

60 |

4. 报告issue:issues

61 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.alibaba.asyncload 5 | asyncload 6 | 1.0.1-SNAPSHOT 7 | jar 8 | asyncload 9 | https://github.com/alibaba/asyncload 10 | 11 | 12 | org.sonatype.oss 13 | oss-parent 14 | 7 15 | 16 | 17 | 18 | agapple 19 | http://agapple.iteye.com 20 | jianghang115@gmail.com 21 | 8 22 | 23 | 24 | 25 | 26 | Apache License, Version 2.0 27 | http://www.apache.org/licenses/LICENSE-2.0 28 | 29 | 30 | 31 | 32 | git@github.com:alibaba/asyncload.git 33 | scm:git:git@github.com:alibaba/asyncload.git 34 | scm:git:git@github.com:alibaba/asyncload.git 35 | 36 | 37 | 38 | UTF-8 39 | 40 | false 41 | true 42 | 43 | 1.6 44 | 1.6 45 | UTF-8 46 | 47 | 48 | 49 | 50 | org.springframework 51 | spring 52 | 2.5.6 53 | 54 | 55 | asm 56 | asm 57 | 3.1 58 | 59 | 60 | cglib 61 | cglib 62 | 2.2 63 | 64 | 65 | oro 66 | oro 67 | 2.0.8 68 | 69 | 70 | 71 | junit 72 | junit 73 | 4.4 74 | test 75 | 76 | 77 | org.springframework 78 | spring-test 79 | 2.5.6 80 | test 81 | 82 | 83 | javassist 84 | javassist 85 | 3.11.0.GA 86 | test 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.jvnet.wagon-svn 94 | wagon-svn 95 | 1.9 96 | 97 | 98 | org.apache.maven.wagon 99 | wagon-http-shared 100 | 1.0-beta-7 101 | 102 | 103 | 104 | 105 | org.apache.maven.plugins 106 | maven-compiler-plugin 107 | 108 | ${java_source_version} 109 | ${java_target_version} 110 | ${file_encoding} 111 | 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-eclipse-plugin 116 | 2.5.1 117 | 118 | 119 | 120 | .settings/org.eclipse.core.resources.prefs 121 | 122 | =${file_encoding}${line.separator}]]> 123 | 124 | 125 | 126 | 127 | 128 | 129 | org.apache.maven.plugins 130 | maven-surefire-plugin 131 | 2.5 132 | 133 | 134 | **/*Test.java 135 | 136 | 137 | **/*NoRunTest.java 138 | 139 | 140 | 141 | 142 | src/main/java 143 | src/test/java 144 | 145 | 146 | src/main/resources 147 | 148 | **/* 149 | 150 | 151 | **/.svn/ 152 | 153 | 154 | 155 | 156 | 157 | src/test/resources 158 | 159 | **/* 160 | 161 | 162 | **/.svn/ 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | sonatype-nexus-snapshots 171 | Sonatype Nexus Snapshots 172 | https://oss.sonatype.org/content/repositories/snapshots/ 173 | 174 | 175 | sonatype-nexus-staging 176 | Nexus Release Repository 177 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/AsyncLoadConfig.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 对应异步加载工具的关注点 8 | * 9 | * @author jianghang 2011-1-22 上午12:06:48 10 | */ 11 | public class AsyncLoadConfig { 12 | 13 | public static final Long DEFAULT_TIME_OUT = 0L; // 默认不设置超时,保持系统兼容性 14 | private volatile Long defaultTimeout = DEFAULT_TIME_OUT; // 单位ms 15 | private volatile Boolean needBarrierSupport = false; // 默认不开启,如果设置了开启不调用AsyncLoadBarrier.await()会有内存泄漏,必须注意 16 | private volatile Boolean needThreadLocalSupport = false; // 默认不开启,如果启用可以共享ThreadLocal,需慎用 17 | private Map matches; 18 | 19 | public AsyncLoadConfig(){ 20 | } 21 | 22 | public AsyncLoadConfig(Long defaultTimeout){ 23 | this.defaultTimeout = defaultTimeout; 24 | } 25 | 26 | public AsyncLoadConfig cloneConfig() { 27 | AsyncLoadConfig config = new AsyncLoadConfig(); 28 | config.setDefaultTimeout(this.getDefaultTimeout()); 29 | config.setNeedBarrierSupport(this.getNeedBarrierSupport()); 30 | config.setNeedThreadLocalSupport(this.getNeedThreadLocalSupport()); 31 | config.setMatches(this.getMatches()); // map对象直接是个引用复制 32 | return config; 33 | } 34 | 35 | // ===================== setter / getter ==================== 36 | 37 | public Map getMatches() { 38 | if (matches == null) { 39 | matches = new HashMap(); 40 | matches.put(AsyncLoadMethodMatch.TRUE, defaultTimeout); 41 | } 42 | 43 | return matches; 44 | } 45 | 46 | public void setMatches(Map matches) { 47 | this.matches = matches; 48 | } 49 | 50 | public Long getDefaultTimeout() { 51 | return defaultTimeout; 52 | } 53 | 54 | public void setDefaultTimeout(Long defaultTimeout) { 55 | this.defaultTimeout = defaultTimeout; 56 | } 57 | 58 | public Boolean getNeedBarrierSupport() { 59 | return needBarrierSupport; 60 | } 61 | 62 | public void setNeedBarrierSupport(Boolean needBarrierSupport) { 63 | this.needBarrierSupport = needBarrierSupport; 64 | } 65 | 66 | public Boolean getNeedThreadLocalSupport() { 67 | return needThreadLocalSupport; 68 | } 69 | 70 | public void setNeedThreadLocalSupport(Boolean needThreadLocalSupport) { 71 | this.needThreadLocalSupport = needThreadLocalSupport; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/AsyncLoadExecutor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.BlockingQueue; 5 | import java.util.concurrent.LinkedBlockingQueue; 6 | import java.util.concurrent.RejectedExecutionHandler; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import com.alibaba.asyncload.impl.pool.AsyncLoadCallable; 10 | import com.alibaba.asyncload.impl.pool.AsyncLoadFuture; 11 | import com.alibaba.asyncload.impl.pool.AsyncLoadThreadPool; 12 | import com.alibaba.asyncload.impl.pool.NamedThreadFactory; 13 | 14 | /** 15 | * 异步加载的具体执行任务者, 支持Runable和Callable两种 16 | * 17 | * @author jianghang 2011-1-21 下午11:32:31 18 | */ 19 | public class AsyncLoadExecutor { 20 | 21 | public static final int DEFAULT_POOL_SIZE = 20; 22 | public static final int DEFAULT_ACCEPT_COUNT = 100; 23 | public static final HandleMode DEFAULT_MODE = HandleMode.REJECT; 24 | private int poolSize; 25 | private int acceptCount; // 等待队列长度,避免无限制提交请求 26 | private HandleMode mode; // 默认为拒绝服务,用于控制accept队列满了以后的处理方式 27 | private AsyncLoadThreadPool pool; 28 | private volatile boolean isInit = false; 29 | 30 | enum HandleMode { 31 | REJECT, CALLERRUN; 32 | } 33 | 34 | public AsyncLoadExecutor(){ 35 | this(DEFAULT_POOL_SIZE, DEFAULT_ACCEPT_COUNT, DEFAULT_MODE); 36 | } 37 | 38 | public AsyncLoadExecutor(int poolSize){ 39 | this(poolSize, DEFAULT_ACCEPT_COUNT, DEFAULT_MODE); 40 | } 41 | 42 | public AsyncLoadExecutor(int poolSize, int acceptCount){ 43 | this(poolSize, acceptCount, DEFAULT_MODE); 44 | } 45 | 46 | public AsyncLoadExecutor(int poolSize, int acceptCount, HandleMode mode){ 47 | this.poolSize = poolSize; 48 | this.acceptCount = acceptCount; 49 | this.mode = mode; 50 | } 51 | 52 | public void initital() { 53 | if (isInit == false) { 54 | RejectedExecutionHandler handler = getHandler(mode); 55 | BlockingQueue queue = getBlockingQueue(acceptCount, mode); 56 | // 构造pool池 57 | this.pool = new AsyncLoadThreadPool(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue, 58 | new NamedThreadFactory(), handler); 59 | 60 | isInit = true; 61 | } 62 | } 63 | 64 | public void destory() { 65 | if (isInit && pool != null) { 66 | pool.shutdown(); 67 | pool = null; 68 | 69 | isInit = false; 70 | } 71 | } 72 | 73 | public AsyncLoadFuture submit(AsyncLoadCallable task) { 74 | return pool.submit(task); 75 | } 76 | 77 | // ==================== help method =========================== 78 | 79 | private BlockingQueue getBlockingQueue(int acceptCount, HandleMode mode) { 80 | if (acceptCount < 0) { 81 | return new LinkedBlockingQueue(); 82 | } else if (acceptCount == 0) { 83 | return new ArrayBlockingQueue(1); // 等于0时等价于队列1 84 | } else { 85 | return new ArrayBlockingQueue(acceptCount); 86 | } 87 | } 88 | 89 | private RejectedExecutionHandler getHandler(HandleMode mode) { 90 | return HandleMode.REJECT == mode ? new AsyncLoadThreadPool.AbortPolicy() : new AsyncLoadThreadPool.CallerRunsPolicy(); 91 | } 92 | 93 | // ====================== setter / getter ========================== 94 | 95 | public void setPoolSize(int poolSize) { 96 | this.poolSize = poolSize; 97 | } 98 | 99 | public void setAcceptCount(int acceptCount) { 100 | this.acceptCount = acceptCount; 101 | } 102 | 103 | public void setMode(HandleMode mode) { 104 | this.mode = mode; 105 | } 106 | 107 | public void setMode(String mode) { 108 | this.mode = HandleMode.valueOf(mode); 109 | } 110 | 111 | // ======================= help method ========================== 112 | 113 | @Override 114 | public String toString() { 115 | return "AsyncLoadExecutor [ poolSize=" + poolSize + ", acceptCount=" + acceptCount + ", mode=" + mode + "]"; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/AsyncLoadMethodMatch.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * 异步加载机制 方法匹配对象定义 7 | * 8 | * @author jianghang 2011-1-21 下午09:49:29 9 | */ 10 | public interface AsyncLoadMethodMatch { 11 | 12 | AsyncLoadMethodMatch TRUE = new AsyncLoadTrueMethodMatcher(); // 默认提供返回always true的实现 13 | 14 | boolean matches(Method method); 15 | 16 | } 17 | 18 | class AsyncLoadTrueMethodMatcher implements AsyncLoadMethodMatch { 19 | 20 | public boolean matches(Method method) { 21 | return true; 22 | } 23 | 24 | public String toString() { 25 | return "AsyncLoadTrueMethodMatcher.TURE"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/AsyncLoadProxy.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 4 | 5 | /** 6 | * 异步加载proxy工厂,创建对应的Proxy Service,当前默认实现为{@linkplain AsyncLoadEnhanceProxy} 7 | * 8 | *
 9 |  * 简单事例代码:
10 |  *  // 初始化config
11 |  *  AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l);
12 |  *  // 初始化executor
13 |  *  AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100);
14 |  *  executor.initital();
15 |  *  // 初始化proxy
16 |  *  AsyncLoadEnhanceProxy<AsyncLoadTestService> proxy = new AsyncLoadEnhanceProxy<AsyncLoadTestService>();
17 |  *  proxy.setService(asyncLoadTestService);
18 |  *  proxy.setConfig(config);
19 |  *  proxy.setExecutor(executor);
20 |  *  proxy.setTargetClass(AsyncLoadTestService.class); //指定代理的目标对象
21 |  *  // 执行测试
22 |  *  AsyncLoadTestService service = proxy.getProxy();
23 |  * 
24 | * 25 | * @author jianghang 2011-1-21 下午08:26:32 26 | */ 27 | public interface AsyncLoadProxy { 28 | 29 | public T getProxy(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/AsyncLoadEnhanceProxy.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl; 2 | 3 | import java.lang.reflect.Method; 4 | import java.lang.reflect.Modifier; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.Set; 8 | import java.util.concurrent.Future; 9 | 10 | import net.sf.cglib.proxy.Callback; 11 | import net.sf.cglib.proxy.CallbackFilter; 12 | import net.sf.cglib.proxy.Dispatcher; 13 | import net.sf.cglib.proxy.Enhancer; 14 | import net.sf.cglib.proxy.MethodInterceptor; 15 | import net.sf.cglib.proxy.MethodProxy; 16 | 17 | import com.alibaba.asyncload.AsyncLoadConfig; 18 | import com.alibaba.asyncload.AsyncLoadExecutor; 19 | import com.alibaba.asyncload.AsyncLoadMethodMatch; 20 | import com.alibaba.asyncload.AsyncLoadProxy; 21 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 22 | import com.alibaba.asyncload.impl.helper.AsyncLoadProxyRepository; 23 | import com.alibaba.asyncload.impl.helper.AsyncLoadReflectionHelper; 24 | import com.alibaba.asyncload.impl.pool.AsyncLoadCallable; 25 | import com.alibaba.asyncload.impl.util.AsyncLoadBarrier; 26 | import com.alibaba.asyncload.impl.util.AsyncLoadUtils; 27 | 28 | /** 29 | * 基于cglib enhance proxy的实现 30 | * 31 | *
 32 |  * 参数说明:
 33 |  * 1. targetClass : 用于明确cglib生成的目标对象类型。比如一般的service都有一个接口,但serviceImpl有时已经被进行一次cglib代理,生成了final对象,这里可以指定targetClass为其接口对象
 34 |  * 
35 | * 36 | * @author jianghang 2011-1-21 下午10:56:39 37 | */ 38 | public class AsyncLoadEnhanceProxy implements AsyncLoadProxy { 39 | 40 | private T service; 41 | private AsyncLoadConfig config; 42 | private AsyncLoadExecutor executor; 43 | private Class targetClass; 44 | 45 | public AsyncLoadEnhanceProxy(){ 46 | } 47 | 48 | public AsyncLoadEnhanceProxy(T service, AsyncLoadExecutor executor){ 49 | this(service, new AsyncLoadConfig(), executor); 50 | } 51 | 52 | public AsyncLoadEnhanceProxy(T service, AsyncLoadConfig config, AsyncLoadExecutor executor){ 53 | this.service = service; 54 | this.config = config; 55 | this.executor = executor; 56 | this.targetClass = (Class) service.getClass();// 默认的代理class对象即为service 57 | } 58 | 59 | public T getProxy() { 60 | validate(); 61 | return getProxyInternal(); 62 | } 63 | 64 | /** 65 | * 相应的检查方法 66 | */ 67 | private void validate() { 68 | AsyncLoadUtils.notNull(service, "service should not be null"); 69 | AsyncLoadUtils.notNull(config, "config should not be null"); 70 | AsyncLoadUtils.notNull(executor, "executor should not be null"); 71 | 72 | if (Modifier.isFinal(targetClass.getModifiers())) { // 目前暂不支持final类型的处理,以后可以考虑使用jdk 73 | // proxy 74 | throw new AsyncLoadException("Enhance proxy not support final class :" + targetClass.getName()); 75 | } 76 | 77 | if (!Modifier.isPublic(targetClass.getModifiers())) { 78 | // 处理如果是非public属性,则不进行代理,强制访问会出现IllegalAccessException,比如一些内部类或者匿名类不允许直接访问 79 | throw new AsyncLoadException("Enhance proxy not support private/protected class :" + targetClass.getName()); 80 | } 81 | } 82 | 83 | class AsyncLoadCallbackFilter implements CallbackFilter { 84 | 85 | public int accept(Method method) { 86 | // 预先进行匹配,直接计算好需要处理的method,避免动态匹配浪费性能 87 | if (AsyncLoadObject.class.isAssignableFrom(method.getDeclaringClass())) {// 判断对应的方法是否属于AsyncLoadObject 88 | return 0; // for AsyncLoadServiceInterceptor 89 | } else { 90 | Map matches = config.getMatches(); 91 | Set methodMatchs = matches.keySet(); 92 | if (methodMatchs != null && !methodMatchs.isEmpty()) { 93 | for (Iterator methodMatch = methodMatchs.iterator(); methodMatch.hasNext();) { 94 | if (methodMatch.next().matches(method)) { 95 | return 2; // for AsyncLoadInterceptor 96 | } 97 | } 98 | } 99 | return 1; // for AsyncLoadDirect 100 | } 101 | } 102 | } 103 | 104 | class AsyncLoadServiceInterceptor implements MethodInterceptor { 105 | 106 | public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 107 | if ("_getOriginalClass".equals(method.getName())) { 108 | return getOriginalClass(); 109 | } 110 | throw new AsyncLoadException("method[" + method.getName() + "] is not support!"); 111 | } 112 | 113 | private Object getOriginalClass() { 114 | return targetClass; 115 | } 116 | } 117 | 118 | class AsyncLoadDirect implements Dispatcher { 119 | 120 | public Object loadObject() throws Exception { 121 | return service; 122 | } 123 | 124 | } 125 | 126 | class AsyncLoadInterceptor implements MethodInterceptor { 127 | 128 | public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 129 | Long timeout = getMatchTimeout(method); 130 | final Object finObj = service; 131 | final Object[] finArgs = args; 132 | final Method finMethod = method; 133 | 134 | Class returnClass = method.getReturnType(); 135 | if (Void.TYPE.isAssignableFrom(returnClass)) {// 判断返回值是否为void 136 | // 不处理void的函数调用 137 | return finMethod.invoke(finObj, finArgs); 138 | } else if (!Modifier.isPublic(returnClass.getModifiers())) { 139 | // 处理如果是非public属性,则不进行代理,强制访问会出现IllegalAccessException,比如一些内部类或者匿名类不允许直接访问 140 | return finMethod.invoke(finObj, finArgs); 141 | } else if (Modifier.isFinal(returnClass.getModifiers())) { 142 | // 处理特殊的final类型,目前暂不支持,后续可采用jdk proxy 143 | return finMethod.invoke(finObj, finArgs); 144 | } else if (returnClass.isPrimitive() || returnClass.isArray()) { 145 | // 不处理特殊类型,因为无法使用cglib代理 146 | return finMethod.invoke(finObj, finArgs); 147 | } else if (returnClass == Object.class) { 148 | // 针对返回对象是Object类型,不做代理。没有具体的method,代理没任何意义 149 | return finMethod.invoke(finObj, finArgs); 150 | } else { 151 | Future future = executor.submit(new AsyncLoadCallable() { 152 | 153 | public Object call() throws Exception { 154 | try { 155 | return finMethod.invoke(finObj, finArgs);// 需要直接委托对应的finObj(service)进行处理 156 | } catch (Throwable e) { 157 | throw new AsyncLoadException("future invoke error!", e); 158 | } 159 | } 160 | 161 | public AsyncLoadConfig getConfig() { 162 | return config; 163 | } 164 | }); 165 | // 够造一个返回的AsyncLoadResult 166 | AsyncLoadResult result = new AsyncLoadResult(returnClass, future, timeout); 167 | // 继续返回一个代理对象 168 | AsyncLoadObject asyncProxy = (AsyncLoadObject) result.getProxy(); 169 | // 添加到barrier中 170 | if (config.getNeedBarrierSupport()) { 171 | AsyncLoadBarrier.addTask((AsyncLoadObject) asyncProxy); 172 | } 173 | // 返回对象 174 | return asyncProxy; 175 | } 176 | 177 | } 178 | 179 | /** 180 | * 返回对应的匹配的timeout时间,一定能找到对应的匹配点 181 | * 182 | * @param method 183 | * @return 184 | */ 185 | private Long getMatchTimeout(Method method) { 186 | Map matches = config.getMatches(); 187 | Set> entrys = matches.entrySet(); 188 | if (entrys != null && !entrys.isEmpty()) { 189 | for (Iterator> iter = entrys.iterator(); iter.hasNext();) { 190 | Map.Entry entry = iter.next(); 191 | if (entry.getKey().matches(method)) { 192 | return entry.getValue(); 193 | } 194 | } 195 | } 196 | 197 | return config.getDefaultTimeout(); 198 | } 199 | } 200 | 201 | // =========================== help mehotd ================================= 202 | 203 | /** 204 | * 优先从Repository进行获取ProxyClass,创建对应的object 205 | * 206 | * @return 207 | */ 208 | private T getProxyInternal() { 209 | Class proxyClass = AsyncLoadProxyRepository.getProxy(targetClass.getName()); 210 | if (proxyClass == null) { 211 | Enhancer enhancer = new Enhancer(); 212 | if (targetClass.isInterface()) { // 判断是否为接口,优先进行接口代理可以解决service为final 213 | enhancer.setInterfaces(new Class[] { targetClass }); 214 | } else { 215 | enhancer.setSuperclass(targetClass); 216 | } 217 | enhancer.setCallbackTypes(new Class[] { AsyncLoadServiceInterceptor.class, AsyncLoadDirect.class, 218 | AsyncLoadInterceptor.class }); 219 | enhancer.setCallbackFilter(new AsyncLoadCallbackFilter()); 220 | proxyClass = enhancer.createClass(); 221 | // 注册proxyClass 222 | AsyncLoadProxyRepository.registerProxy(targetClass.getName(), proxyClass); 223 | } 224 | 225 | Enhancer.registerCallbacks(proxyClass, new Callback[] { new AsyncLoadServiceInterceptor(), 226 | new AsyncLoadDirect(), new AsyncLoadInterceptor() }); 227 | try { 228 | return (T) AsyncLoadReflectionHelper.newInstance(proxyClass); 229 | } finally { 230 | // clear thread callbacks to allow them to be gc'd 231 | Enhancer.registerStaticCallbacks(proxyClass, null); 232 | } 233 | } 234 | 235 | // ====================== setter / getter =========================== 236 | 237 | public void setService(T service) { 238 | this.service = service; 239 | if (targetClass == null) { 240 | this.targetClass = (Class) service.getClass(); 241 | } 242 | } 243 | 244 | public void setConfig(AsyncLoadConfig config) { 245 | this.config = config; 246 | } 247 | 248 | public void setExecutor(AsyncLoadExecutor executor) { 249 | this.executor = executor; 250 | } 251 | 252 | public void setTargetClass(Class targetClass) { 253 | this.targetClass = targetClass; 254 | } 255 | 256 | } 257 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/AsyncLoadObject.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl; 2 | 3 | /** 4 | * 内部对象,不允许外部直接使用: 并行加载的Model对象,返回的代理Model对象都会实现该接口 5 | * 6 | *
 7 |  * 提供客户端获取代理对象的一些内部状态,一般不建议直接操作该类:
 8 |  * 1. null : 判断真实的model是否为null
 9 |  * 2. status : 返回当前model的执行情况,比如运行状态{@linkplain AsyncLoadStatus.Status}, 相关时间
10 |  * 3. originalClass : 返回原先的代理的原始class实例,因为使用代理后会丢失Annotation,Generic,Field数据,所以需要直接操作原始class
11 |  * 4. originalResult : 返回原先的代理的返回原始结果
12 |  * 
13 | * 14 | * @author jianghang 2011-4-4 下午04:06:53 15 | */ 16 | public interface AsyncLoadObject { 17 | 18 | /** 19 | * @return 判断真实的model是否为null 20 | */ 21 | boolean _isNull(); 22 | 23 | /** 24 | * @return 并行加载的运行状态 25 | */ 26 | AsyncLoadStatus _getStatus(); 27 | 28 | /** 29 | * @return 原始的被代理的class对象 30 | */ 31 | Class _getOriginalClass(); 32 | 33 | /** 34 | * @return 原始的结果对象 35 | */ 36 | Object _getOriginalResult(); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/AsyncLoadPerl5RegexpMethodMatcher.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Arrays; 5 | 6 | import org.apache.oro.text.regex.MalformedPatternException; 7 | import org.apache.oro.text.regex.Pattern; 8 | import org.apache.oro.text.regex.PatternMatcher; 9 | import org.apache.oro.text.regex.Perl5Compiler; 10 | import org.apache.oro.text.regex.Perl5Matcher; 11 | 12 | import com.alibaba.asyncload.AsyncLoadMethodMatch; 13 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 14 | import com.alibaba.asyncload.impl.util.AsyncLoadUtils; 15 | 16 | /** 17 | * 基于Perl5 oro进行正则匹配的matcher 18 | * 19 | * @author jianghang 2011-1-21 下午10:40:44 20 | */ 21 | public class AsyncLoadPerl5RegexpMethodMatcher implements AsyncLoadMethodMatch { 22 | 23 | // 匹配字符串 24 | private String[] patterns = new String[0]; 25 | private String[] excludedPatterns = new String[0]; 26 | // 匹配对象 27 | private Pattern[] compiledPatterns = new Pattern[0]; 28 | private Pattern[] compiledExclusionPatterns = new Pattern[0]; 29 | private boolean excludeOveride = false; // 是否排除条件优先 30 | private PatternMatcher matcher = new Perl5Matcher(); // 对应的Matcher 31 | 32 | public boolean matches(Method method) { 33 | String signatureString = method.getName(); 34 | if (excludeOveride) { 35 | return matchesExclusionFirst(signatureString); 36 | } else { 37 | return matchesFirst(signatureString); 38 | } 39 | } 40 | 41 | /** 42 | * 优先采取pattern 43 | * 44 | * @param signatureString 45 | * @return 46 | */ 47 | private boolean matchesFirst(String signatureString) { 48 | // 优先采取pattern 49 | for (int i = 0; i < this.compiledPatterns.length; i++) { 50 | boolean matched = this.matcher.matches(signatureString, this.compiledPatterns[i]); 51 | if (matched) {// 如果匹配,再进行excludePattern过滤 52 | for (int j = 0; j < this.compiledExclusionPatterns.length; j++) { 53 | boolean excluded = this.matcher.matches(signatureString, this.compiledExclusionPatterns[j]); 54 | if (excluded) { 55 | return false; 56 | } 57 | } 58 | return true; 59 | } 60 | } 61 | 62 | return false; 63 | } 64 | 65 | /** 66 | * 优先采取excludePattern 67 | * 68 | * @param signatureString 69 | * @return 70 | */ 71 | private boolean matchesExclusionFirst(String signatureString) { 72 | // 优先采取excludePattern 73 | boolean excluded = false; 74 | for (int i = 0; i < this.compiledExclusionPatterns.length; i++) { 75 | excluded |= this.matcher.matches(signatureString, this.compiledExclusionPatterns[i]); 76 | } 77 | 78 | return !excluded; 79 | } 80 | 81 | /** 82 | * 编译对应的pattern,返回oro的Pattern对象 83 | */ 84 | private Pattern[] compilePatterns(String[] source) { 85 | Perl5Compiler compiler = new Perl5Compiler(); 86 | Pattern[] destination = new Pattern[source.length]; 87 | for (int i = 0; i < source.length; i++) { 88 | try { 89 | destination[i] = compiler.compile(source[i], Perl5Compiler.READ_ONLY_MASK); 90 | } catch (MalformedPatternException ex) { 91 | throw new AsyncLoadException(ex.getMessage()); 92 | } 93 | } 94 | return destination; 95 | } 96 | 97 | // ===================== setter / getter ============================ 98 | 99 | public void setExcludeOveride(boolean excludeOveride) { 100 | this.excludeOveride = excludeOveride; 101 | } 102 | 103 | public void setPattern(String pattern) { 104 | setPatterns(new String[] { pattern }); 105 | } 106 | 107 | public void setPatterns(String[] patterns) { 108 | AsyncLoadUtils.notEmpty(patterns, "'patterns' cannot be null or empty."); 109 | this.patterns = patterns; 110 | this.compiledPatterns = compilePatterns(patterns); 111 | } 112 | 113 | public void setExcludedPattern(String excludedPattern) { 114 | setExcludedPatterns(new String[] { excludedPattern }); 115 | } 116 | 117 | public void setExcludedPatterns(String[] excludedPatterns) { 118 | AsyncLoadUtils.notEmpty(excludedPatterns, "excludedPatterns must not be empty"); 119 | this.excludedPatterns = excludedPatterns; 120 | this.compiledExclusionPatterns = compilePatterns(excludedPatterns); 121 | 122 | } 123 | 124 | @Override 125 | public String toString() { 126 | return "AsyncLoadPerl5RegexpMethodMatcher [excludeOveride=" + excludeOveride + ", excludedPatterns=" 127 | + Arrays.toString(excludedPatterns) + ", patterns=" + Arrays.toString(patterns) + "]"; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/AsyncLoadResult.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.concurrent.ExecutionException; 5 | import java.util.concurrent.Future; 6 | import java.util.concurrent.TimeUnit; 7 | import java.util.concurrent.TimeoutException; 8 | 9 | import net.sf.cglib.proxy.Callback; 10 | import net.sf.cglib.proxy.CallbackFilter; 11 | import net.sf.cglib.proxy.Enhancer; 12 | import net.sf.cglib.proxy.LazyLoader; 13 | import net.sf.cglib.proxy.MethodInterceptor; 14 | import net.sf.cglib.proxy.MethodProxy; 15 | 16 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 17 | import com.alibaba.asyncload.impl.helper.AsyncLoadProxyRepository; 18 | import com.alibaba.asyncload.impl.helper.AsyncLoadReflectionHelper; 19 | import com.alibaba.asyncload.impl.pool.AsyncLoadFuture; 20 | 21 | /** 22 | * 异步加载返回的proxy result 23 | * 24 | * @author jianghang 2011-1-21 下午09:45:14 25 | */ 26 | public class AsyncLoadResult { 27 | 28 | private Class returnClass; 29 | private Future future; 30 | private Long timeout; 31 | 32 | public AsyncLoadResult(Class returnClass, Future future, Long timeout){ 33 | this.returnClass = returnClass; 34 | this.future = future; 35 | this.timeout = timeout; 36 | } 37 | 38 | public Object getProxy() { 39 | Class proxyClass = AsyncLoadProxyRepository.getProxy(returnClass.getName()); 40 | if (proxyClass == null) { // 进行cache处理 41 | Enhancer enhancer = new Enhancer(); 42 | if (returnClass.isInterface()) {// 判断returnClass是否为接口 43 | enhancer.setInterfaces(new Class[] { AsyncLoadObject.class, returnClass }); // 设置默认的接口 44 | } else { 45 | enhancer.setInterfaces(new Class[] { AsyncLoadObject.class });// 设置默认的接口 46 | enhancer.setSuperclass(returnClass); 47 | } 48 | enhancer.setCallbackFilter(new AsyncLoadCallbackFilter()); 49 | enhancer.setCallbackTypes(new Class[] { AsyncLoadResultInterceptor.class, AsyncLoadObjectInterceptor.class }); 50 | proxyClass = enhancer.createClass(); 51 | 52 | AsyncLoadProxyRepository.registerProxy(returnClass.getName(), proxyClass); 53 | } 54 | 55 | Enhancer.registerCallbacks(proxyClass, new Callback[] { new AsyncLoadResultInterceptor(), 56 | new AsyncLoadObjectInterceptor() }); 57 | try { 58 | // 返回对象 59 | return AsyncLoadReflectionHelper.newInstance(proxyClass); 60 | } finally { 61 | // clear thread callbacks to allow them to be gc'd 62 | Enhancer.registerStaticCallbacks(proxyClass, null); 63 | } 64 | 65 | } 66 | 67 | /** 68 | * future.get()的返回对象 69 | * 70 | * @return 71 | * @throws InterruptedException 72 | * @throws ExecutionException 73 | */ 74 | private Object loadFuture() throws AsyncLoadException { 75 | try { 76 | // 使用cglib lazyLoader,避免每次调用future 77 | if (timeout <= 0) {// <=0处理,不进行超时控制 78 | return future.get(); 79 | } else { 80 | return future.get(timeout, TimeUnit.MILLISECONDS); 81 | } 82 | } catch (TimeoutException e) { 83 | future.cancel(true); 84 | throw new AsyncLoadException(e); 85 | } catch (InterruptedException e) { 86 | throw new AsyncLoadException(e); 87 | } catch (Exception e) { 88 | throw new AsyncLoadException(e); 89 | } 90 | } 91 | 92 | class AsyncLoadCallbackFilter implements CallbackFilter { 93 | 94 | public int accept(Method method) { 95 | // 预先进行匹配,直接计算好需要处理的method,避免动态匹配浪费性能 96 | if (AsyncLoadObject.class.isAssignableFrom(method.getDeclaringClass())) {// 判断对应的方法是否属于AsyncLoadObject 97 | return 1; 98 | } else { 99 | // 其他全部返回0 100 | return 0; 101 | } 102 | 103 | } 104 | } 105 | 106 | /** 107 | * 针对AsyncLoadObject方法的实现 108 | * 109 | * @author jianghang 2011-4-4 下午04:22:09 110 | */ 111 | class AsyncLoadObjectInterceptor implements MethodInterceptor { 112 | 113 | public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 114 | if ("_isNull".equals(method.getName())) { 115 | return isNull(); 116 | } else if ("_getStatus".equals(method.getName())) { 117 | return getStatus(); 118 | } else if ("_getOriginalClass".equals(method.getName())) { 119 | return getOriginalClass(); 120 | } else if ("_getOriginalResult".equals(method.getName())) { 121 | return getOriginalResut(); 122 | } 123 | 124 | throw new AsyncLoadException("method[" + method.getName() + "] is not support!"); 125 | } 126 | 127 | private Object isNull() throws Throwable { 128 | try { 129 | return loadFuture() == null; // 判断原始对象是否为null 130 | } catch (Exception e) { 131 | // 如果出现异常,直接返回为true,这里不再抛出异常,没意义,因为我这里想要的是isNull判断 132 | // 在最后get()属性时会返回对应future执行的异常信息 133 | // return true; 134 | throw e; 135 | } 136 | } 137 | 138 | private Object getStatus() { 139 | long startTime = 0; 140 | long endTime = 0; 141 | if (future instanceof AsyncLoadFuture) { 142 | startTime = ((AsyncLoadFuture) future).getStartTime(); 143 | endTime = ((AsyncLoadFuture) future).getEndTime(); 144 | } 145 | AsyncLoadStatus.Status status = null; 146 | if (future.isCancelled()) { // 如果已经完成 147 | // 在timeout时会标记future为cancel,所有可由cancel状态判断是否为timeout 148 | status = AsyncLoadStatus.Status.TIMEOUT; 149 | } else if (future.isDone()) { 150 | status = AsyncLoadStatus.Status.DONE; 151 | } else { 152 | // 这里并不严格区分是否正在运行或者在Executor进行排队中,比如Executor直接拒绝Reject 153 | status = AsyncLoadStatus.Status.RUN; 154 | if (endTime == 0) { 155 | endTime = System.currentTimeMillis();// 设置为当前时间 156 | } 157 | } 158 | 159 | return new AsyncLoadStatus(status, startTime, (endTime - startTime)); 160 | } 161 | 162 | private Object getOriginalClass() { 163 | return returnClass; 164 | } 165 | 166 | private Object getOriginalResut() throws Throwable { 167 | return loadFuture(); 168 | } 169 | 170 | } 171 | 172 | /** 173 | * 针对model对象的所有方法进行代理实现 174 | * 175 | * @author jianghang 2011-4-4 下午04:24:40 176 | */ 177 | class AsyncLoadResultInterceptor implements LazyLoader { 178 | 179 | public Object loadObject() throws Exception { 180 | return loadFuture(); 181 | } 182 | 183 | } 184 | 185 | } 186 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/AsyncLoadService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl; 2 | 3 | /** 4 | * 并行加载的service类,默认生成的代理proxy会实现该接口. 5 | *

6 | * {@linkplain AsyncLoadService}和{@linkplain AsyncLoadObject}关系:对应的是service和model之间的概念,调用proxy service的某个方法,会创建一个proxy 7 | * model 8 | * 9 | *

10 |  * 提供客户端获取代理serivce的一些内部状态,一般不建议直接操作该类:
11 |  * 1. originalClass : 返回原先的代理的原始class实例,因为使用代理后会丢失Annotation,Generic,Field数据,所以需要直接操作原始class
12 |  * 
13 |  * TODO : 后续可添加一些profile的统计信息,比如当前service并行加载的model有多少,每个代理方法的平均响应时间信息等。暂时没这需求,先不实现
14 |  * 
15 | * 16 | * @author jianghang 2011-4-4 下午04:06:53 17 | */ 18 | public interface AsyncLoadService { 19 | 20 | /** 21 | * @return 原始的被代理的class对象 22 | */ 23 | Class _getOriginalClass(); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/AsyncLoadStatus.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl; 2 | 3 | /** 4 | * 记录一下并行加载执行的一些状态信息: 5 | * 6 | *
 7 |  * 1. status : 代表asyncload的运行状态
 8 |  * 2. startTime 开始运行asyncload时间点,记录的是System.currentTimeMillis()时间
 9 |  * 3. costTime: 总共消耗时间,单位ms
10 |  *     *. 如果是status==DONE,则返回正常执行的时间, costTime = (完成时间点 - startTime)
11 |  *     *. 如果status==TIMEOUT,则返回实际使用的时间,costTime = (超时时间点 -startTime)
12 |  *     *. 如果status==RUN ,则返回当前使用的时间,costTime = (当前时间 - startTIme)
13 |  * 
14 | * 15 | * @author jianghang 2011-4-4 下午07:13:56 16 | */ 17 | public class AsyncLoadStatus { 18 | 19 | final private long starTime; // 执行开始时间 20 | final private long costTime; 21 | final private Status status; 22 | 23 | public AsyncLoadStatus(Status status, long startTime, long costTime){ 24 | this.status = status; 25 | this.starTime = startTime; 26 | this.costTime = costTime; 27 | } 28 | 29 | public static enum Status { 30 | /** 执行中 */ 31 | RUN, 32 | /** 已超时 */ 33 | TIMEOUT, 34 | /** 已完成(可能是正常结束/有异常退出) */ 35 | DONE; 36 | 37 | public boolean isRun() { 38 | return this == RUN; 39 | } 40 | 41 | public boolean isTimeout() { 42 | return this == TIMEOUT; 43 | } 44 | 45 | public boolean isDone() { 46 | return this == DONE; 47 | } 48 | } 49 | 50 | public long getStarTime() { 51 | return starTime; 52 | } 53 | 54 | public long getCostTime() { 55 | return costTime; 56 | } 57 | 58 | public Status getStatus() { 59 | return status; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/exceptions/AsyncLoadException.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.exceptions; 2 | 3 | /** 4 | * 并行加载自定义异常 5 | * 6 | * @author jianghang 2011-4-1 下午05:06:37 7 | */ 8 | public class AsyncLoadException extends RuntimeException { 9 | 10 | private static final long serialVersionUID = -2128834565845654572L; 11 | 12 | public AsyncLoadException(){ 13 | super(); 14 | } 15 | 16 | public AsyncLoadException(String message, Throwable cause){ 17 | super(message, cause); 18 | } 19 | 20 | public AsyncLoadException(String message){ 21 | super(message); 22 | } 23 | 24 | public AsyncLoadException(Throwable cause){ 25 | super(cause); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/helper/AsyncLoadProxyRepository.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.helper; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * 提供对应的proxy仓库,避免重复创建对应的class 8 | * 9 | * @author jianghang 2011-1-24 下午03:36:17 10 | */ 11 | public class AsyncLoadProxyRepository { 12 | 13 | private static Map reponsitory = new ConcurrentHashMap(); 14 | 15 | /** 16 | * 如果存在对应的key的ProxyClass就返回,没有则返回null 17 | * 18 | * @param key 19 | * @return 20 | */ 21 | public static Class getProxy(String key) { 22 | return reponsitory.get(key); 23 | } 24 | 25 | /** 26 | * 注册对应的proxyClass到仓库中 27 | * 28 | * @param key 29 | * @param proxyClass 30 | */ 31 | public static void registerProxy(String key, Class proxyClass) { 32 | if (!reponsitory.containsKey(key)) { // 避免重复提交 33 | synchronized (reponsitory){ 34 | if (!reponsitory.containsKey(key)){ 35 | reponsitory.put(key, proxyClass); 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/helper/AsyncLoadReflectionHelper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.helper; 2 | 3 | import java.lang.reflect.Array; 4 | import java.lang.reflect.Constructor; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | import net.sf.cglib.core.ReflectUtils; 10 | import net.sf.cglib.reflect.FastClass; 11 | import net.sf.cglib.reflect.FastMethod; 12 | 13 | /** 14 | * AyncLoad中常用的一些反射方法 15 | * 16 | * @author jianghang 2011-3-29 下午09:55:12 17 | */ 18 | public class AsyncLoadReflectionHelper { 19 | 20 | private static final Map primitiveValueMap = new HashMap(16); 21 | private static Map fastClassCache = new ConcurrentHashMap(); 22 | private static Map fastMethodCache = new ConcurrentHashMap(); 23 | 24 | static { 25 | primitiveValueMap.put(Boolean.class, Boolean.FALSE); 26 | primitiveValueMap.put(Byte.class, Byte.valueOf((byte) 0)); 27 | primitiveValueMap.put(Character.class, Character.valueOf((char) 0)); 28 | primitiveValueMap.put(Short.class, Short.valueOf((short) 0)); 29 | primitiveValueMap.put(Double.class, Double.valueOf(0)); 30 | primitiveValueMap.put(Float.class, Float.valueOf(0)); 31 | primitiveValueMap.put(Integer.class, Integer.valueOf(0)); 32 | primitiveValueMap.put(Long.class, Long.valueOf(0)); 33 | primitiveValueMap.put(boolean.class, Boolean.FALSE); 34 | primitiveValueMap.put(byte.class, Byte.valueOf((byte) 0)); 35 | primitiveValueMap.put(char.class, Character.valueOf((char) 0)); 36 | primitiveValueMap.put(short.class, Short.valueOf((short) 0)); 37 | primitiveValueMap.put(double.class, Double.valueOf(0)); 38 | primitiveValueMap.put(float.class, Float.valueOf(0)); 39 | primitiveValueMap.put(int.class, Integer.valueOf(0)); 40 | primitiveValueMap.put(long.class, Long.valueOf(0)); 41 | 42 | } 43 | 44 | /** 45 | * 特殊处理,允许通过带参数的constructor创建对象 46 | * 47 | * @param type 48 | * @return 49 | */ 50 | public static Object newInstance(Class type) { 51 | Constructor _constructor = null; 52 | Object[] _constructorArgs = new Object[0]; 53 | try { 54 | _constructor = type.getConstructor(new Class[] {});// 先尝试默认的空构造函数 55 | } catch (NoSuchMethodException e) { 56 | // ignore 57 | } 58 | 59 | if (_constructor == null) {// 没有默认的构造函数,尝试别的带参数的函数 60 | Constructor[] constructors = type.getConstructors(); 61 | if (constructors.length == 0) { 62 | throw new UnsupportedOperationException("Class[" + type.getName() + "] has no public constructors"); 63 | } 64 | _constructor = constructors[0];// 默认取第一个参数 65 | Class[] params = _constructor.getParameterTypes(); 66 | _constructorArgs = new Object[params.length]; 67 | for (int i = 0; i < params.length; i++) { 68 | _constructorArgs[i] = getDefaultValue(params[i]); 69 | } 70 | } 71 | 72 | return ReflectUtils.newInstance(_constructor, _constructorArgs); 73 | } 74 | 75 | public static FastMethod getMethod(Class clazz, String methodName) { 76 | return getMethod(clazz, methodName, new Class[] {}); 77 | } 78 | 79 | /** 80 | * 根据信息查询FastMethod,已经有cache实现。 81 | * 82 | * @param clazz 83 | * @param methodName 84 | * @param parameterTypes 85 | * @return 86 | */ 87 | public static FastMethod getMethod(Class clazz, String methodName, Class... parameterTypes) { 88 | String clazzName = clazz.getName(); 89 | String methodKey = clazzName + "#" + methodName; 90 | 91 | FastMethod method = fastMethodCache.get(methodKey); 92 | if (null == method) { 93 | FastClass fc = fastClassCache.get(clazzName); 94 | if (null == fc) { 95 | fc = FastClass.create(clazz); 96 | fastClassCache.put(clazzName, fc); 97 | } 98 | method = fc.getMethod(methodName, parameterTypes); 99 | if (null == method) { 100 | fastMethodCache.put(methodKey, method); 101 | } 102 | } 103 | 104 | return method; 105 | } 106 | 107 | /** 108 | * 根据class类型返回默认值值 109 | * 110 | * @param cl 111 | * @return 112 | */ 113 | public static Object getDefaultValue(Class cl) { 114 | if (cl.isArray()) {// 处理数组 115 | return Array.newInstance(cl.getComponentType(), 0); 116 | } else if (cl.isPrimitive() || primitiveValueMap.containsKey(cl)) { // 处理原型 117 | return primitiveValueMap.get(cl); 118 | } else { 119 | return AsyncLoadReflectionHelper.newInstance(cl); 120 | // return null; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/pool/AsyncLoadCallable.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.pool; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | import com.alibaba.asyncload.AsyncLoadConfig; 6 | 7 | /** 8 | * 扩展callable,支持{@linkplain AsyncLoadConfig}的传递 9 | * 10 | * @author jianghang 2011-4-27 下午03:42:04 11 | */ 12 | public interface AsyncLoadCallable extends Callable { 13 | 14 | AsyncLoadConfig getConfig(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/pool/AsyncLoadFuture.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.pool; 2 | 3 | import java.util.concurrent.FutureTask; 4 | 5 | import com.alibaba.asyncload.AsyncLoadConfig; 6 | import com.alibaba.asyncload.impl.util.AsyncLoadUtils; 7 | 8 | /** 9 | * 继承J.U.C下的FutureTask,主要的变化点: 10 | * 11 | *
12 |  * 1. 持有提交task的thread引用,用于threadLocal处理.新的pool处理线程可以继承/共享callerThread线程的threadLocal信息
13 |  * 
14 | * 15 | * @author jianghang 2011-3-28 下午10:15:04 16 | */ 17 | public class AsyncLoadFuture extends FutureTask { 18 | 19 | private Thread callerThread; // 记录提交runnable的thread,在ThreadPool中用于提取ThreadLocal 20 | private Thread runnerThread; 21 | private long startTime = 0; // 记录下future开始执行的时间 22 | private long endTime = 0; // 记录下future执行结束时间 23 | private AsyncLoadConfig config; 24 | 25 | public AsyncLoadFuture(AsyncLoadCallable callable){ 26 | super(callable); 27 | callerThread = Thread.currentThread(); 28 | config = callable.getConfig(); 29 | 30 | AsyncLoadUtils.notNull(config, "config is null!"); 31 | } 32 | 33 | @Override 34 | protected void done() { 35 | endTime = System.currentTimeMillis(); // 记录一下时间点,Future在cancel调用,正常完成,或者运行出异常都会回调该方法 36 | } 37 | 38 | @Override 39 | public void run() { 40 | startTime = System.currentTimeMillis(); 41 | runnerThread = Thread.currentThread(); // 记录的下具体pool中的runnerThread,可能是caller自己 42 | super.run(); 43 | } 44 | 45 | // =============== setter / getter =============== 46 | 47 | public Thread getCallerThread() { 48 | return callerThread; 49 | } 50 | 51 | public Thread getRunnerThread() { 52 | return runnerThread; 53 | } 54 | 55 | public long getStartTime() { 56 | return startTime; 57 | } 58 | 59 | public long getEndTime() { 60 | return endTime; 61 | } 62 | 63 | public AsyncLoadConfig getConfig() { 64 | return config; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/pool/AsyncLoadThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.pool; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.concurrent.BlockingQueue; 5 | import java.util.concurrent.RejectedExecutionHandler; 6 | import java.util.concurrent.ThreadFactory; 7 | import java.util.concurrent.ThreadPoolExecutor; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import org.springframework.util.ReflectionUtils; 11 | 12 | /** 13 | * 扩展了J.U.C的ThreadPoolExecutor,主要扩展点说明: 14 | * 15 | *
 16 |  * 1. 覆写newTaskFor函数,返回自定义的{@linkplain AsyncLoadFuture}
 17 |  * 2. 增强了Pool池中的Worker线程,会自动复制caller Thread的threadLocal信息,几点考虑:
 18 |  *   a. Worker线程为pool的内部管理对象,在操作ThreadLocal信息时安全性上不存在问题,持有的引用在task完成后也可以正常释放。ThreadLocal引用在Worker线程中的生命周期<=Caller Thread线程
 19 |  *   b. 做为并行异步加载,一个主要的设计思想就是对业务尽可能的透明,尽可能的减少使用陷井,所以这里通过非正常手段实现了ThreadLocal的支持,实属无奈
 20 |  * 
21 | * 22 | * @author jianghang 2011-3-28 下午09:56:32 23 | */ 24 | public class AsyncLoadThreadPool extends ThreadPoolExecutor { 25 | 26 | private static final Field threadLocalField = ReflectionUtils.findField(Thread.class, "threadLocals"); 27 | private static final Field inheritableThreadLocalField = ReflectionUtils.findField(Thread.class, 28 | "inheritableThreadLocals"); 29 | static { 30 | // 强制的声明accessible 31 | ReflectionUtils.makeAccessible(threadLocalField); 32 | ReflectionUtils.makeAccessible(inheritableThreadLocalField); 33 | } 34 | 35 | // 继承自ThreadPoolExecutor的构造函数 36 | public AsyncLoadThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, 37 | BlockingQueue workQueue){ 38 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); 39 | } 40 | 41 | public AsyncLoadThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, 42 | BlockingQueue workQueue, RejectedExecutionHandler handler){ 43 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); 44 | } 45 | 46 | public AsyncLoadThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, 47 | BlockingQueue workQueue, ThreadFactory threadFactory, 48 | RejectedExecutionHandler handler){ 49 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); 50 | } 51 | 52 | public AsyncLoadThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, 53 | BlockingQueue workQueue, ThreadFactory threadFactory){ 54 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); 55 | } 56 | 57 | public AsyncLoadFuture submit(AsyncLoadCallable task) { 58 | if (task == null) throw new NullPointerException(); 59 | AsyncLoadFuture ftask = new AsyncLoadFuture(task); // 使用自定义的Future 60 | execute(ftask); 61 | return ftask; 62 | } 63 | 64 | // ====================== 扩展点 ========================== 65 | 66 | @Override 67 | public void execute(Runnable command) { 68 | if (command instanceof AsyncLoadFuture) { 69 | AsyncLoadFuture afuture = (AsyncLoadFuture) command; 70 | boolean flag = afuture.getConfig().getNeedThreadLocalSupport(); 71 | if (flag) { 72 | Thread thread = Thread.currentThread(); 73 | if (ReflectionUtils.getField(threadLocalField, thread) == null) { 74 | // 创建一个空的ThreadLocal,立马写回去 75 | new ThreadLocal(); // 这时会在runner线程产生一空记录的ThreadLocalMap记录 76 | } 77 | if (ReflectionUtils.getField(inheritableThreadLocalField, thread) == null) { 78 | // 创建一个空的ThreadLocal,立马写回去 79 | new InheritableThreadLocal(); // 可继承的ThreadLocal 80 | } 81 | } 82 | } 83 | 84 | super.execute(command);// 调用父类进行提交 85 | } 86 | 87 | @Override 88 | protected void beforeExecute(Thread t, Runnable command) { 89 | // 在执行之前处理下ThreadPool的属性继承 90 | if (command instanceof AsyncLoadFuture) { 91 | AsyncLoadFuture afuture = (AsyncLoadFuture) command; 92 | boolean flag = afuture.getConfig().getNeedThreadLocalSupport(); 93 | if (flag) { 94 | initThreadLocal(threadLocalField, afuture.getCallerThread(), t); 95 | initThreadLocal(inheritableThreadLocalField, afuture.getCallerThread(), t); 96 | } 97 | } 98 | 99 | super.beforeExecute(t, command); 100 | } 101 | 102 | @Override 103 | protected void afterExecute(Runnable command, Throwable t) { 104 | // 在执行结束后清理下ThreadPool的属性,GC处理 105 | if (command instanceof AsyncLoadFuture) { 106 | AsyncLoadFuture afuture = (AsyncLoadFuture) command; 107 | boolean flag = afuture.getConfig().getNeedThreadLocalSupport(); 108 | if (flag) { 109 | recoverThreadLocal(threadLocalField, afuture.getCallerThread(), afuture.getRunnerThread()); 110 | recoverThreadLocal(inheritableThreadLocalField, afuture.getCallerThread(), afuture.getRunnerThread()); 111 | } 112 | } 113 | 114 | super.afterExecute(command, t); 115 | } 116 | 117 | private void initThreadLocal(Field field, Thread caller, Thread runner) { 118 | if (caller == null || runner == null) { 119 | return; 120 | } 121 | // 主要考虑这样的情况: 122 | // 1. 123 | // 如果caller线程没有使用ThreadLocal对象,而异步加载的runner线程执行中使用了ThreadLocal对象,则需要复制对象到caller线程上 124 | // 2. 125 | // 后续caller,多个runner线程有使用ThreadLocal对象,使用的是同一个引用,直接set都是针对同一个ThreadLocal,所以以后就不需要进行合并 126 | 127 | // 因为在提交Runnable时已经同步创建了一个ThreadLocalMap对象,所以runner线程只需要复制caller对应的引用即可,不需要进行合并,简化处理 128 | // threadlocal属性复制,注意是引用复制 129 | Object callerThreadLocalMap = ReflectionUtils.getField(field, caller); 130 | if (callerThreadLocalMap != null) { 131 | ReflectionUtils.setField(field, runner, callerThreadLocalMap);// 复制caller的信息到runner线程上 132 | } else { 133 | // 这个分支不会出现,因为在execute提交的时候已经添加 134 | } 135 | } 136 | 137 | private void recoverThreadLocal(Field field, Thread caller, Thread runner) { 138 | if (runner == null) { 139 | return; 140 | } 141 | // 清理runner线程的ThreadLocal,为下一个task服务 142 | ReflectionUtils.setField(field, runner, null); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/pool/NamedThreadFactory.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.pool; 2 | 3 | import java.util.concurrent.ThreadFactory; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | /** 7 | * @author jianghang 2011-4-1 下午06:50:26 8 | */ 9 | public class NamedThreadFactory implements ThreadFactory { 10 | 11 | final private static String DEFAULT_NAME = "asyncload-pool"; 12 | final private String name; 13 | final private boolean daemon; 14 | final private ThreadGroup group; 15 | final private AtomicInteger threadNumber = new AtomicInteger(0); 16 | 17 | public NamedThreadFactory(){ 18 | this(DEFAULT_NAME, true); 19 | } 20 | 21 | public NamedThreadFactory(String name, boolean daemon){ 22 | this.name = name; 23 | this.daemon = daemon; 24 | SecurityManager s = System.getSecurityManager(); 25 | group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); 26 | } 27 | 28 | public Thread newThread(Runnable r) { 29 | Thread t = new Thread(group, r, name + "-" + threadNumber.getAndIncrement(), 0); 30 | t.setDaemon(daemon); 31 | if (t.getPriority() != Thread.NORM_PRIORITY) { 32 | t.setPriority(Thread.NORM_PRIORITY); 33 | } 34 | return t; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/spring/AsyncLoadFactoryBean.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.spring; 2 | 3 | import org.springframework.beans.factory.FactoryBean; 4 | import org.springframework.beans.factory.InitializingBean; 5 | 6 | import com.alibaba.asyncload.AsyncLoadConfig; 7 | import com.alibaba.asyncload.AsyncLoadExecutor; 8 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 9 | import com.alibaba.asyncload.impl.util.AsyncLoadUtils; 10 | 11 | /** 12 | * 基于spring FactoryBean实现的一套AsyncLoad机制,声明式 13 | * 14 | * @author jianghang 2011-1-24 下午07:00:17 15 | */ 16 | public class AsyncLoadFactoryBean implements FactoryBean, InitializingBean { 17 | 18 | private Object target; 19 | private Class targetClass; 20 | private AsyncLoadExecutor executor; 21 | private AsyncLoadConfig config; 22 | 23 | public Object getObject() throws Exception { 24 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(target, config, executor); 25 | proxy.setTargetClass(targetClass); 26 | return proxy.getProxy(); // 返回对应的代理对象 27 | } 28 | 29 | public Class getObjectType() { 30 | return targetClass; 31 | } 32 | 33 | public boolean isSingleton() { 34 | return true; // 因为使用proxy,所以设置为true 35 | } 36 | 37 | public void afterPropertiesSet() throws Exception { 38 | // check 39 | AsyncLoadUtils.notNull(config, "config should not be null!"); 40 | AsyncLoadUtils.notNull(executor, "executor should not be null!"); 41 | AsyncLoadUtils.notNull(target, "target should not be null!"); 42 | } 43 | 44 | // ======================= setter / getter ====================== 45 | 46 | public void setExecutor(AsyncLoadExecutor executor) { 47 | this.executor = executor; 48 | } 49 | 50 | public void setConfig(AsyncLoadConfig config) { 51 | this.config = config; 52 | } 53 | 54 | public void setTarget(Object target) { 55 | this.target = target; 56 | } 57 | 58 | public void setTargetClass(Class targetClass) { 59 | this.targetClass = targetClass; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/spring/AsyncLoadInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.spring; 2 | 3 | import org.aopalliance.intercept.MethodInterceptor; 4 | import org.aopalliance.intercept.MethodInvocation; 5 | 6 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 7 | import com.alibaba.asyncload.impl.template.AsyncLoadCallback; 8 | import com.alibaba.asyncload.impl.template.AsyncLoadTemplate; 9 | 10 | /** 11 | * 开发基于拦截器实现的并行加载,注意依赖{@linkplain AsyncLoadTemplate} 12 | * 13 | *
14 |  * 适用于以下情况:
15 |  * 1. 原先的service对象已经被进行cglib代理,并行加载可以做为其中的一个代理进行织入
16 |  * 2. 希望通过BeanNameAutoProxyCreator进行自动代理配置,不想影响原先的bean配置
17 |  * 
18 |  * 设计注意:
19 |  * 1. 这里依赖{@linkplain AsyncLoadTemplate}进行代码块的并行加载控制,而不能对原先的service进行代理(会产生死循环)
20 |  * 2. 并不直接提供method match的机制,希望是可以直接利用spring提供的PointCut进行控制
21 |  * 
22 | * 23 | * 使用示例配置: 24 | * 25 | *
26 |  *     
27 |  *         
28 |  *         
29 |  *             
30 |  *                 *DataFeeder
31 |  *             
32 |  *         
33 |  *         
34 |  *             
35 |  *                 asyncLoadInterceptor
36 |  *             
37 |  *         
38 |  *     
39 |  * 
40 | * 41 | * @author jianghang 2011-4-1 下午04:52:51 42 | */ 43 | public class AsyncLoadInterceptor implements MethodInterceptor { 44 | 45 | private AsyncLoadTemplate asyncLoadTemplate; 46 | 47 | public Object invoke(MethodInvocation invocation) throws Throwable { 48 | final MethodInvocation temp = invocation; 49 | return asyncLoadTemplate.execute(new AsyncLoadCallback() { 50 | 51 | public Object doAsyncLoad() { 52 | try { 53 | return temp.proceed(); 54 | } catch (Throwable e) { 55 | throw new AsyncLoadException("AsyncLoadInterceptor invoke error!", e); 56 | } 57 | } 58 | }, invocation.getMethod().getReturnType()); // 这里指定了返回目标class 59 | 60 | } 61 | 62 | // =============== setter / getter ================= 63 | 64 | public void setAsyncLoadTemplate(AsyncLoadTemplate asyncLoadTemplate) { 65 | this.asyncLoadTemplate = asyncLoadTemplate; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/spring/CompositeAutoProxyCreator.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.spring; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.HashSet; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | import org.aopalliance.aop.Advice; 12 | import org.springframework.aop.Advisor; 13 | import org.springframework.aop.framework.AopInfrastructureBean; 14 | import org.springframework.aop.framework.ProxyConfig; 15 | import org.springframework.aop.framework.ProxyFactoryBean; 16 | import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator; 17 | import org.springframework.beans.BeansException; 18 | import org.springframework.beans.factory.BeanClassLoaderAware; 19 | import org.springframework.beans.factory.BeanFactory; 20 | import org.springframework.beans.factory.BeanFactoryAware; 21 | import org.springframework.beans.factory.config.BeanPostProcessor; 22 | import org.springframework.core.Ordered; 23 | import org.springframework.transaction.interceptor.TransactionProxyFactoryBean; 24 | import org.springframework.util.ClassUtils; 25 | import org.springframework.util.PatternMatchUtils; 26 | import org.springframework.util.ReflectionUtils; 27 | import org.springframework.util.StringUtils; 28 | 29 | /** 30 | * 提供一种机制:无侵入的拦截机制,与现有的bean定义进行融合。实现自定义的{@linkplain BeanPostProcessor}进行替换,部分代码copy from 31 | * {@linkplain AbstractAutoProxyCreator} 32 | * 33 | *
 34 |  * 融合的规则:
 35 |  * 1. 原先的bean是{@linkplain ProxyFactoryBean},则将自己的拦截器定义和proxy bean的定义进行融合,只是会合并原先的拦截器定义,其他的不做融合
 36 |  *    可通过applyCommonInterceptorsFirst=true/false指定顺序.如果是false则{@linkplain CompositeAutoProxyCreator}定义的拦截器排在后面
 37 |  * 2. 如果原先的bean是除{@linkplain ProxyFactoryBean}的bean,则尝试自动创建ProxyFactoryBean,对应的拦截器也仅是所配置的拦截器列表,不会进行自动的扫描和装配
 38 |  * 3. 其他的类似:{@linkplain TransactionProxyFactoryBean}并不会进行一个融合的处理
 39 |  * 
 40 |  * 
41 | * 42 | * @author jianghang 2011-4-25 上午10:43:12 43 | */ 44 | public class CompositeAutoProxyCreator extends ProxyConfig implements BeanPostProcessor, Ordered, BeanClassLoaderAware, BeanFactoryAware, AopInfrastructureBean { 45 | 46 | private static final long serialVersionUID = 8458055362270662345L; 47 | private static final Field interceptorNamesField = ReflectionUtils.findField(ProxyFactoryBean.class, 48 | "interceptorNames"); 49 | 50 | private ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader(); 51 | private boolean classLoaderConfigured = false; 52 | private BeanFactory beanFactory; 53 | private List beanNames; 54 | private int order = Integer.MAX_VALUE; 55 | private String[] interceptorNames = new String[0]; 56 | private boolean applyCommonInterceptorsFirst = false; 57 | private final Set nonAdvisedBeans = Collections.synchronizedSet(new HashSet()); 58 | 59 | public Object postProcessBeforeInitialization(Object bean, String beanName) { 60 | // 不做处理 61 | return bean; 62 | } 63 | 64 | public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 65 | if (bean != null) { 66 | Object cacheKey = getCacheKey(bean.getClass(), beanName); 67 | return wrapIfNecessary(bean, beanName, cacheKey); 68 | } 69 | 70 | return bean; 71 | } 72 | 73 | protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { 74 | if (this.nonAdvisedBeans.contains(cacheKey)) { 75 | return bean; 76 | } 77 | if (isInfrastructureClass(bean.getClass())) { 78 | this.nonAdvisedBeans.add(cacheKey); 79 | return bean; 80 | } 81 | // 不能进行代理cache,singleton的实现有spring core核心机制来保证,如果是singleton不会回调多次 82 | // Create proxy if we have advice. 83 | if (this.beanNames != null) { 84 | for (Iterator it = this.beanNames.iterator(); it.hasNext();) { 85 | String mappedName = (String) it.next(); 86 | if (isMatch(beanName, mappedName)) { 87 | if (ProxyFactoryBean.class.isAssignableFrom(bean.getClass())) { 88 | ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean; 89 | String[] orignInterceptorNames = getInterceptorFromProxyFactoryBean(proxyFactoryBean); 90 | String[] newInterceptorNames = new String[orignInterceptorNames.length 91 | + interceptorNames.length]; 92 | if (applyCommonInterceptorsFirst) {// 如果是true,则将Auto-proxy的拦截器定义到最前面 93 | // 构造新的的拦截器列表 94 | System.arraycopy(interceptorNames, 0, newInterceptorNames, 0, interceptorNames.length); 95 | System.arraycopy(orignInterceptorNames, 0, newInterceptorNames, interceptorNames.length, 96 | orignInterceptorNames.length); 97 | } else { 98 | System.arraycopy(orignInterceptorNames, 0, newInterceptorNames, 0, 99 | orignInterceptorNames.length); 100 | System.arraycopy(interceptorNames, 0, newInterceptorNames, orignInterceptorNames.length, 101 | interceptorNames.length); 102 | } 103 | // 重新设置新的inteceptorNames 104 | proxyFactoryBean.setInterceptorNames(newInterceptorNames); 105 | return proxyFactoryBean; 106 | } else { 107 | // 如果是单例,对应的代理bean对象为同一个 108 | ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); 109 | proxyFactoryBean.setBeanFactory(beanFactory); 110 | proxyFactoryBean.setBeanClassLoader(proxyClassLoader); 111 | proxyFactoryBean.setInterceptorNames(interceptorNames); 112 | proxyFactoryBean.copyFrom(this); // 拷贝对应的一些Proxy config 113 | proxyFactoryBean.setTarget(bean); 114 | return proxyFactoryBean.getObject(); 115 | } 116 | } 117 | } 118 | } 119 | 120 | this.nonAdvisedBeans.add(cacheKey); 121 | return bean; 122 | } 123 | 124 | // =========================== helper method ================================ 125 | 126 | private String[] getInterceptorFromProxyFactoryBean(ProxyFactoryBean bean) { 127 | synchronized (interceptorNamesField) { 128 | try { 129 | interceptorNamesField.setAccessible(true); 130 | try { 131 | Object obj = interceptorNamesField.get(bean); 132 | return obj != null ? (String[]) obj : new String[0]; 133 | } catch (Exception e) { 134 | throw new RuntimeException(e); 135 | } 136 | } finally { 137 | interceptorNamesField.setAccessible(false); 138 | } 139 | } 140 | 141 | } 142 | 143 | /** 144 | * 对应的内存cache的key 145 | */ 146 | protected Object getCacheKey(Class beanClass, String beanName) { 147 | return beanClass.getName() + "_" + beanName; 148 | } 149 | 150 | /** 151 | * 不对基础的框架类做auto-proxy 152 | * 153 | * @param beanClass 154 | * @return 155 | */ 156 | protected boolean isInfrastructureClass(Class beanClass) { 157 | return Advisor.class.isAssignableFrom(beanClass) || Advice.class.isAssignableFrom(beanClass) 158 | || AopInfrastructureBean.class.isAssignableFrom(beanClass); 159 | } 160 | 161 | /** 162 | * 返回是否匹配,支持简单的通配符: "xxx*", "*xxx" "*xxx*" 163 | */ 164 | protected boolean isMatch(String beanName, String mappedName) { 165 | return PatternMatchUtils.simpleMatch(mappedName, beanName); 166 | } 167 | 168 | // ========================= setter / getter =========================== 169 | 170 | public final void setOrder(int order) { 171 | this.order = order; 172 | } 173 | 174 | public final int getOrder() { 175 | return this.order; 176 | } 177 | 178 | public void setInterceptorNames(String[] interceptorNames) { 179 | this.interceptorNames = interceptorNames; 180 | } 181 | 182 | public void setApplyCommonInterceptorsFirst(boolean applyCommonInterceptorsFirst) { 183 | this.applyCommonInterceptorsFirst = applyCommonInterceptorsFirst; 184 | } 185 | 186 | public void setBeanClassLoader(ClassLoader classLoader) { 187 | if (!this.classLoaderConfigured) { 188 | this.proxyClassLoader = classLoader; 189 | } 190 | } 191 | 192 | public void setBeanFactory(BeanFactory beanFactory) { 193 | this.beanFactory = beanFactory; 194 | } 195 | 196 | public void setBeanNames(String[] beanNames) { 197 | this.beanNames = new ArrayList(beanNames.length); 198 | for (int i = 0; i < beanNames.length; i++) { 199 | this.beanNames.add(StringUtils.trimWhitespace(beanNames[i])); 200 | } 201 | } 202 | 203 | } 204 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/template/AsyncLoadCallback.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.template; 2 | 3 | /** 4 | * 对应AyncLoad模板的回调函数 5 | * 6 | * @author jianghang 2011-1-24 下午07:38:10 7 | */ 8 | public interface AsyncLoadCallback { 9 | 10 | public R doAsyncLoad(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/template/AsyncLoadTemplate.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.template; 2 | 3 | import java.lang.reflect.GenericArrayType; 4 | import java.lang.reflect.Modifier; 5 | import java.lang.reflect.ParameterizedType; 6 | import java.lang.reflect.Type; 7 | import java.util.concurrent.Future; 8 | 9 | import com.alibaba.asyncload.AsyncLoadConfig; 10 | import com.alibaba.asyncload.AsyncLoadExecutor; 11 | import com.alibaba.asyncload.impl.AsyncLoadObject; 12 | import com.alibaba.asyncload.impl.AsyncLoadResult; 13 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 14 | import com.alibaba.asyncload.impl.pool.AsyncLoadCallable; 15 | import com.alibaba.asyncload.impl.util.AsyncLoadBarrier; 16 | import com.alibaba.asyncload.impl.util.AsyncLoadUtils; 17 | 18 | /** 19 | * 基于template模式提供的一套AsyncLoad机制,编程式 20 | * 21 | * @author jianghang 2011-1-24 下午07:01:07 22 | */ 23 | public class AsyncLoadTemplate { 24 | 25 | private AsyncLoadExecutor executor; 26 | private AsyncLoadConfig config = new AsyncLoadConfig(); 27 | 28 | /** 29 | * 异步执行callback模板,设置默认的超时时间,同时返回对应的proxy model,执行AsyncLoad 30 | * 31 | * @param 32 | * @param callback 33 | * @return 34 | */ 35 | public R execute(AsyncLoadCallback callback) { 36 | return execute(callback, config); 37 | } 38 | 39 | /** 40 | * 异步执行callback模板,同时返回对应的proxy model,执行AsyncLoad 41 | * 42 | * @param 43 | * @param callback 44 | * @param timeout 45 | * @return 46 | */ 47 | public R execute(final AsyncLoadCallback callback, long timeout) { 48 | AsyncLoadUtils.notNull(callback, "callback is null!"); 49 | 50 | Type type = callback.getClass().getGenericInterfaces()[0]; 51 | if (!(type instanceof ParameterizedType)) { 52 | // 用户不指定AsyncLoadCallBack的泛型信息 53 | throw new AsyncLoadException("you should specify AsyncLoadCallBack for R type, ie: AsyncLoadCallBack"); 54 | } 55 | Class returnClass = (Class) getGenericClass((ParameterizedType) type, 0); 56 | 57 | AsyncLoadConfig copy = config.cloneConfig(); 58 | copy.setDefaultTimeout(timeout); 59 | return execute(callback, returnClass, copy); 60 | } 61 | 62 | /** 63 | * 异步执行callback模板,设置默认的超时时间,同时返回对应的proxy model,执行AsyncLoad 64 | * 65 | * @param 66 | * @param callback 67 | * @param returnClass 期望的返回对象class 68 | * @return 69 | */ 70 | public R execute(AsyncLoadCallback callback, Class returnClass) { 71 | return execute(callback, returnClass, config); 72 | } 73 | 74 | /** 75 | * 异步执行callback模板,同时返回对应的proxy model,执行AsyncLoad 76 | * 77 | * @param 78 | * @param callback 79 | * @param returnClass 期望的返回对象class 80 | * @param timeout 81 | * @return 82 | */ 83 | public R execute(final AsyncLoadCallback callback, Class returnClass, long timeout) { 84 | AsyncLoadConfig copy = config.cloneConfig(); 85 | copy.setDefaultTimeout(timeout); 86 | return execute(callback, returnClass, copy); 87 | } 88 | 89 | /** 90 | * 异步执行callback模板,传递config对象 91 | * 92 | * @param 93 | * @param callback 94 | * @param config 95 | * @return 96 | */ 97 | public R execute(final AsyncLoadCallback callback, AsyncLoadConfig config) { 98 | AsyncLoadUtils.notNull(callback, "callback is null!"); 99 | 100 | Type type = callback.getClass().getGenericInterfaces()[0]; 101 | if (!(type instanceof ParameterizedType)) { 102 | // 用户不指定AsyncLoadCallBack的泛型信息 103 | throw new AsyncLoadException("you should specify AsyncLoadCallBack for R type, ie: AsyncLoadCallBack"); 104 | } 105 | Class returnClass = (Class) getGenericClass((ParameterizedType) type, 0); 106 | return execute(callback, returnClass, config); 107 | } 108 | 109 | /** 110 | * 异步执行callback模板,传递config对象 111 | * 112 | * @param 113 | * @param callback 114 | * @param returnClass 115 | * @param config 116 | * @return 117 | */ 118 | public R execute(final AsyncLoadCallback callback, Class returnClass, AsyncLoadConfig config) { 119 | AsyncLoadUtils.notNull(callback, "callback is null!"); 120 | AsyncLoadUtils.notNull(returnClass, "returnClass is null!"); 121 | AsyncLoadUtils.notNull(config, "config is null!"); 122 | 123 | if (Void.TYPE.isAssignableFrom(returnClass)) {// 判断返回值是否为void 124 | // 不处理void的函数调用 125 | return callback.doAsyncLoad(); 126 | } else if (!Modifier.isPublic(returnClass.getModifiers())) { 127 | // 处理如果是非public属性,则不进行代理,强制访问会出现IllegalAccessException,比如一些内部类或者匿名类不允许直接访问 128 | return callback.doAsyncLoad(); 129 | } else if (Modifier.isFinal(returnClass.getModifiers())) { 130 | // 处理特殊的final类型,目前暂不支持,后续可采用jdk proxy 131 | return callback.doAsyncLoad(); 132 | } else if (returnClass.isPrimitive() || returnClass.isArray()) { 133 | // 不处理特殊类型,因为无法使用cglib代理 134 | return callback.doAsyncLoad(); 135 | } else if (returnClass == Object.class) { 136 | // 针对返回对象是Object类型,不做代理。没有具体的method,代理没任何意义 137 | return callback.doAsyncLoad(); 138 | } else { 139 | final AsyncLoadConfig copy = config; 140 | Future future = executor.submit(new AsyncLoadCallable() { 141 | 142 | public R call() throws Exception { 143 | return callback.doAsyncLoad(); 144 | } 145 | 146 | public AsyncLoadConfig getConfig() { 147 | return copy; 148 | } 149 | }); 150 | // 够造一个返回的AsyncLoadResult 151 | AsyncLoadResult result = new AsyncLoadResult(returnClass, future, config.getDefaultTimeout()); 152 | // 继续返回一个代理对象 153 | R asyncProxy = (R) result.getProxy(); 154 | // 添加到barrier中 155 | if (config.getNeedBarrierSupport()) { 156 | AsyncLoadBarrier.addTask((AsyncLoadObject) asyncProxy); 157 | } 158 | // 返回对象 159 | return asyncProxy; 160 | } 161 | } 162 | 163 | /** 164 | * 取得范性信息 165 | * 166 | * @param cls 167 | * @param i 168 | * @return 169 | */ 170 | private Class getGenericClass(ParameterizedType parameterizedType, int i) { 171 | Object genericClass = parameterizedType.getActualTypeArguments()[i]; 172 | if (genericClass instanceof ParameterizedType) { // 处理多级泛型 173 | return (Class) ((ParameterizedType) genericClass).getRawType(); 174 | } else if (genericClass instanceof GenericArrayType) { // 处理数组泛型 175 | return (Class) ((GenericArrayType) genericClass).getGenericComponentType(); 176 | } else { 177 | return (Class) genericClass; 178 | } 179 | } 180 | 181 | // ===================== setter / getter ============================= 182 | 183 | public void setExecutor(AsyncLoadExecutor executor) { 184 | this.executor = executor; 185 | } 186 | 187 | public void setConfig(AsyncLoadConfig config) { 188 | this.config = config; 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/util/AsyncLoadBarrier.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.util; 2 | 3 | import com.alibaba.asyncload.impl.AsyncLoadObject; 4 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * 提供一栅栏机制,利用该栅栏可以要求Thread主线程提交的异步所有并行加载单元返回结果
11 | * 说明:如果出现嵌套的并行加载调用,需要自己设置多个点的栅栏。 12 | * 13 | *
14 |  * 比如:主线程调用A方法,A方法中调用B方法和C方法。简化一点说:A -> B ,A -> C
15 |  * 需要在A方法的最后,执行一次barrier.await()操作
16 |  * 同样需要在主线程的最后,再执行一次barrier.await()操作
17 |  * 
18 | * 19 | *
20 |  * barrier使用例子:
21 |  * try {
22 |  * ModelA a = xxService.getModelA(); //提交一个加载单元
23 |  * ModelB b = xxService.getModelB(); //提交一个加载单元
24 |  * } finally { //务必要执行,不然会内有内存泄漏,barrier中会持有临时的加载单元
25 |  *  try {
26 |  *      AsyncLoadBarrier.await();
27 |  *  } catch (InterruptedException ex) {
28 |  *      return;
29 |  *  } catch (AsyncLoadException ex) {
30 |  *      return;
31 |  *  }
32 |  * }
33 |  *  // 通过栅栏之后, ModelA和ModelB数据已正式加载完成
34 |  * 
35 | * 36 | * @author jianghang 2011-4-27 下午02:18:30 37 | */ 38 | public class AsyncLoadBarrier { 39 | 40 | private static ThreadLocal> tasks = new ThreadLocal>() { 41 | 42 | protected List initialValue() { 43 | return new ArrayList(); 44 | } 45 | 46 | }; 47 | 48 | public static void await() throws AsyncLoadException { 49 | List objects = tasks.get(); 50 | try { 51 | for (AsyncLoadObject object : objects) { 52 | object._getOriginalResult();// 调用一个方法,进行阻塞等待结果,内部会返回timeout , interrupt异常等 53 | } 54 | } finally { 55 | objects = null; 56 | tasks.set(new ArrayList()); // 清空掉barrier记录,避免内存泄漏 57 | } 58 | } 59 | 60 | // =================== helper method ================= 61 | 62 | public static void addTask(AsyncLoadObject object) { 63 | // 内部方法,用于提交task 64 | tasks.get().add(object); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/util/AsyncLoadUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.impl.util; 2 | 3 | import net.sf.cglib.proxy.Enhancer; 4 | 5 | import com.alibaba.asyncload.impl.AsyncLoadObject; 6 | import com.alibaba.asyncload.impl.AsyncLoadService; 7 | import com.alibaba.asyncload.impl.AsyncLoadStatus; 8 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 9 | 10 | /** 11 | * 提供给外部的一些AsyncLoad的便利的操作方法 12 | * 13 | * @author jianghang 2011-4-4 下午04:44:26 14 | */ 15 | public class AsyncLoadUtils { 16 | 17 | /** 18 | * Assert that an object is not null . 19 | */ 20 | public static void notNull(Object object, String message) { 21 | if (object == null) { 22 | throw new IllegalArgumentException(message); 23 | } 24 | } 25 | 26 | /** 27 | * Assert that an object is not null . 28 | * 29 | *
 30 |      * Assert.notNull(clazz);
 31 |      * 
32 | */ 33 | public static void notNull(Object object) { 34 | notNull(object, "[Assertion failed] - this argument is required; it must not be null"); 35 | } 36 | 37 | /** 38 | * Assert that an array has elements; that is, it must not be 39 | * null and must have at least one element. 40 | */ 41 | public static void notEmpty(Object[] array, String message) { 42 | if (array == null || array.length == 0) { 43 | throw new IllegalArgumentException(message); 44 | } 45 | } 46 | 47 | /** 48 | * Assert that an array has elements; that is, it must not be 49 | * null and must have at least one element. 50 | */ 51 | public static void notEmpty(Object[] array) { 52 | notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element"); 53 | } 54 | 55 | /** 56 | * 根据model实例,判断一个Model当前是否使用并行加载 57 | * 58 | * @param model 59 | * @return 60 | */ 61 | public static boolean isAsyncLoad(Object model) throws AsyncLoadException { 62 | if (model == null) { 63 | return false; 64 | } 65 | 66 | return isAsyncLoad(model.getClass()); 67 | } 68 | 69 | /** 70 | * 根据model class,判断当前是否使用并行加载 71 | * 72 | * @param model 73 | * @return 74 | */ 75 | public static boolean isAsyncLoad(Class clazz) throws AsyncLoadException { 76 | if (clazz == null) { 77 | return false; 78 | } 79 | // Enhancer.isEnhanced(clazz)判断会进行一个method查找,在整个asyncload工具自身占了比较多时间 80 | return AsyncLoadObject.class.isAssignableFrom(clazz); 81 | } 82 | 83 | /** 84 | * 并行加载会返回一个proxy model对象(永远不会为null),所以为满足以前的if(model == 85 | * null)判断,提供了一个util方法进行处理 86 | * 87 | *
 88 |      * 说明: 
 89 |      * 1. 如果当前model没有采用并行加载,则直接返回model == null判断,兼容处理
 90 |      * 2. 加载model过程中出现异常,该方法直接返回true。对应的异常:并行加载超时异常,service抛出业务异常等
 91 |      * 3. 调用该方法会进行阻塞并行加载,直到结果返回
 92 |      * 
93 | * 94 | * @param model 95 | * @return 96 | */ 97 | public static boolean isNull(Object model) throws AsyncLoadException { 98 | if (!isAsyncLoad(model)) {// 如果不是并行加载model 99 | // throw new 100 | // IllegalArgumentException("model is not run asyncload mode!"); 101 | return model == null; 102 | } else { 103 | return ((AsyncLoadObject) model)._isNull(); // 进行强制转型处理 104 | } 105 | } 106 | 107 | /** 108 | * 执行并行加载后,原先的使用时间统计方式已不在有效,这里提供一个util方法获取底层的并行加载数据状态 109 | * 110 | *
111 |      * 说明: 
112 |      * 1. 如果当前model没有采用并行加载,则直接返回null
113 |      * 2. 调用该方法不会阻塞并行加载
114 |      * 
115 | * 116 | * @param model 117 | * @return 118 | */ 119 | public static AsyncLoadStatus getStatus(Object model) throws AsyncLoadException { 120 | if (!isAsyncLoad(model)) {// 如果不是并行加载model 121 | // throw new 122 | // IllegalArgumentException("model is not run asyncload mode!"); 123 | return null; 124 | } else { 125 | return ((AsyncLoadObject) model)._getStatus(); // 进行强制转型处理 126 | } 127 | } 128 | 129 | /** 130 | * 执行并行加载后,原先的Model对象已经被代理,如Annotation,Generic,Field属性都会丢失。 131 | * 这里提供一个util方法获取原始的model class 132 | * 133 | *
134 |      * 说明: 
135 |      * 1. 如果当前model没有采用并行加载,则直接返回model的class对象
136 |      * 2. 调用该方法不会阻塞并行加载
137 |      * 
138 | * 139 | * @param model 140 | * @return 141 | */ 142 | public static Class getOriginalClass(Object model) throws AsyncLoadException { 143 | if (!isAsyncLoad(model)) {// 如果不是并行加载model 144 | // throw new 145 | // IllegalArgumentException("model is not run asyncload mode!"); 146 | return model.getClass(); 147 | } else { 148 | return ((AsyncLoadObject) model)._getOriginalClass(); // 进行强制转型处理 149 | } 150 | } 151 | 152 | /** 153 | * 执行并行加载后,原先的Model对象已经被代理,这里提供一个util方法获取原始的方法调用的返回对象 154 | * 155 | *
156 |      * 说明: 
157 |      * 1. 如果当前model没有采用并行加载,则直接返回model本身
158 |      * 2. 调用该方法会进行阻塞并行加载
159 |      * 
160 | * 161 | * @param model 162 | * @return 163 | */ 164 | public static Object getOriginalResult(Object model) throws AsyncLoadException { 165 | if (!isAsyncLoad(model)) {// 如果不是并行加载model 166 | // throw new 167 | // IllegalArgumentException("model is not run asyncload mode!"); 168 | return model; 169 | } else { 170 | return ((AsyncLoadObject) model)._getOriginalResult(); // 进行强制转型处理 171 | } 172 | } 173 | 174 | /** 175 | * 实施并行加载后,原先的service对象已经被代理,如Annotation,Generic,Field属性都会丢失。 176 | * 这里提供一个util方法获取原始的service class 177 | * 178 | *
179 |      * 说明: 
180 |      * 1. 如果当前model没有采用并行加载,则直接返回service的class对象
181 |      * 2. 调用该方法不会阻塞并行加载
182 |      * 
183 | * 184 | * @param service代理之前的class,可能是个接口或者具体类 185 | * @return 186 | */ 187 | public static Class getServiceOriginalClass(Object service) throws AsyncLoadException { 188 | Class clazz = service.getClass(); 189 | if (Enhancer.isEnhanced(clazz) && AsyncLoadService.class.isAssignableFrom(clazz)) {// 如果不是并行加载model 190 | // throw new 191 | // IllegalArgumentException("service is not run asyncload mode!"); 192 | return service.getClass(); 193 | } else { 194 | return ((AsyncLoadService) service)._getOriginalClass(); // 进行强制转型处理 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/main/resources/bean-asyncload-sample.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | xxxService 31 | 32 | 33 | 34 | 35 | asyncLoadInterceptor 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/AsyncLoadExecutorTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.ThreadPoolExecutor; 5 | 6 | import junit.framework.Assert; 7 | 8 | import org.junit.Test; 9 | 10 | /** 11 | * 针对executor的单元测试 12 | * 13 | * @author jianghang 2011-1-24 下午09:17:02 14 | */ 15 | public class AsyncLoadExecutorTest extends BaseAsyncLoadNoRunTest { 16 | 17 | private static final String POOL_NAME = "pool"; 18 | 19 | @Test 20 | public void testLifeCycle() { 21 | AsyncLoadExecutor executor = new AsyncLoadExecutor(); 22 | // 启动 23 | executor.initital(); 24 | // 关闭 25 | executor.destory(); 26 | } 27 | 28 | @Test 29 | public void testPoolConfig() { 30 | ThreadPoolExecutor executor = null; 31 | // 创建初始参数 32 | AsyncLoadExecutor def = new AsyncLoadExecutor(); 33 | def.initital(); 34 | 35 | executor = (ThreadPoolExecutor) TestUtils.getField(def, POOL_NAME); 36 | // 检查pool size 37 | Assert.assertEquals(executor.getCorePoolSize(), AsyncLoadExecutor.DEFAULT_POOL_SIZE); 38 | // 检查handler处理模式 39 | boolean result1 = executor.getRejectedExecutionHandler().getClass().isAssignableFrom( 40 | ThreadPoolExecutor.AbortPolicy.class); 41 | 42 | Assert.assertTrue(result1); 43 | // 检查block queue 44 | boolean result2 = executor.getQueue().getClass().isAssignableFrom(ArrayBlockingQueue.class); 45 | Assert.assertTrue(result2); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/AsyncLoadFinalClassTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 8 | 9 | /** 10 | * 测试一下final类+接口方式的代理 11 | * 12 | * @author jianghang 2011-3-31 上午11:50:04 13 | */ 14 | public class AsyncLoadFinalClassTest extends BaseAsyncLoadNoRunTest { 15 | 16 | @Test 17 | public void testStringFinal() { 18 | // 初始化config 19 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 20 | // 初始化executor 21 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 22 | executor.initital(); 23 | // 初始化proxy 24 | String targer = "1234567890"; 25 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 26 | proxy.setService(targer); 27 | proxy.setConfig(config); 28 | proxy.setExecutor(executor); 29 | // java.util.String对象的接口类,因为String是final对象,所以只能设置代理对应的接口类 30 | proxy.setTargetClass(CharSequence.class); 31 | 32 | CharSequence ser = (CharSequence) proxy.getProxy(); 33 | Assert.assertEquals(ser.length(), targer.length()); 34 | System.out.println(ser); 35 | 36 | executor.destory(); 37 | } 38 | 39 | @Test 40 | public void testServiceFinal() { 41 | // 初始化config 42 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 43 | // 初始化executor 44 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 45 | executor.initital(); 46 | // 初始化proxy 47 | FinalService service = new FinalServiceImpl(); 48 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 49 | proxy.setService(service); 50 | proxy.setConfig(config); 51 | proxy.setExecutor(executor); 52 | // FinalServiceImpl是final对象,所以只能设置代理对应的接口类 53 | proxy.setTargetClass(FinalService.class); 54 | 55 | FinalService target = proxy.getProxy(); 56 | int value = 1; 57 | FinalModel model = target.count(value); 58 | Assert.assertEquals(model.getCount(), value); 59 | executor.destory(); 60 | } 61 | 62 | public interface FinalService { 63 | 64 | FinalModel count(int i); 65 | } 66 | 67 | class FinalModel { 68 | 69 | private int count; 70 | 71 | public int getCount() { 72 | return count; 73 | } 74 | 75 | public void setCount(int count) { 76 | this.count = count; 77 | } 78 | 79 | } 80 | 81 | final class FinalServiceImpl implements FinalService { 82 | 83 | public FinalModel count(int i) { 84 | FinalModel model = new FinalModel(); 85 | model.setCount(i); 86 | return model; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/AsyncLoadMethodMatchTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.springframework.util.ReflectionUtils; 8 | 9 | import com.alibaba.asyncload.impl.AsyncLoadPerl5RegexpMethodMatcher; 10 | 11 | /** 12 | * methodMatch匹配测试 13 | * 14 | * @author jianghang 2011-1-29 下午05:06:25 15 | */ 16 | public class AsyncLoadMethodMatchTest extends BaseAsyncLoadNoRunTest { 17 | 18 | private static final String METHOD4 = "doOtherthing"; 19 | private static final String METHOD3 = "doSomething"; 20 | private static final String METHOD2 = "method2"; 21 | private static final String METHOD1 = "method1"; 22 | 23 | @Test 24 | public void testMatch_include() { 25 | AsyncLoadPerl5RegexpMethodMatcher matcher = new AsyncLoadPerl5RegexpMethodMatcher(); 26 | matcher.setPatterns(new String[] { METHOD1, METHOD2 }); 27 | 28 | Method method1 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD1); 29 | Assert.assertTrue(matcher.matches(method1)); 30 | Method method2 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD2); 31 | Assert.assertTrue(matcher.matches(method2)); 32 | Method method3 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD3); 33 | Assert.assertFalse(matcher.matches(method3)); 34 | Method method4 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD4); 35 | Assert.assertFalse(matcher.matches(method4)); 36 | } 37 | 38 | @Test 39 | public void testMatch_exclude() { 40 | AsyncLoadPerl5RegexpMethodMatcher matcher = new AsyncLoadPerl5RegexpMethodMatcher(); 41 | matcher.setPatterns(new String[] { METHOD1, METHOD2 }); 42 | matcher.setExcludedPatterns(new String[] { METHOD2, METHOD4 }); // 使用排除必须基于pattern基础上 43 | 44 | Method method1 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD1); 45 | Assert.assertTrue(matcher.matches(method1)); 46 | Method method2 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD2); 47 | Assert.assertFalse(matcher.matches(method2)); 48 | Method method3 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD3); 49 | Assert.assertFalse(matcher.matches(method3)); 50 | Method method4 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD4); 51 | Assert.assertFalse(matcher.matches(method4)); 52 | } 53 | 54 | @Test 55 | public void testMatch_includeOveride() { 56 | AsyncLoadPerl5RegexpMethodMatcher matcher = new AsyncLoadPerl5RegexpMethodMatcher(); 57 | matcher.setExcludedPatterns(new String[] { METHOD3, METHOD4 }); 58 | matcher.setExcludeOveride(true); 59 | 60 | Method method1 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD1); 61 | Assert.assertTrue(matcher.matches(method1)); 62 | Method method2 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD2); 63 | Assert.assertTrue(matcher.matches(method2)); 64 | Method method3 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD3); 65 | Assert.assertFalse(matcher.matches(method3)); 66 | Method method4 = ReflectionUtils.findMethod(MethodMatchMock.class, METHOD4); 67 | Assert.assertFalse(matcher.matches(method4)); 68 | } 69 | 70 | } 71 | 72 | class MethodMatchMock { 73 | 74 | public void method1() { 75 | 76 | } 77 | 78 | public void method2() { 79 | 80 | } 81 | 82 | public void doSomething() { 83 | 84 | } 85 | 86 | public void doOtherthing() { 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/AsyncLoadProxyTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.RejectedExecutionException; 6 | 7 | import javax.annotation.Resource; 8 | 9 | import junit.framework.Assert; 10 | 11 | import org.junit.Test; 12 | 13 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 14 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 15 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 16 | 17 | public class AsyncLoadProxyTest extends BaseAsyncLoadNoRunTest { 18 | 19 | @Resource(name = "asyncLoadTestService") 20 | private AsyncLoadTestService asyncLoadTestService; 21 | 22 | @Test 23 | public void testProxy() { 24 | // 初始化config 25 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 26 | // 初始化executor 27 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 28 | executor.initital(); 29 | // 初始化proxy 30 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 31 | proxy.setService(asyncLoadTestService); 32 | proxy.setConfig(config); 33 | proxy.setExecutor(executor); 34 | // 执行测试 35 | AsyncLoadTestService service = proxy.getProxy(); 36 | AsyncLoadTestModel model1 = service.getRemoteModel("first", 1000); // 每个请求sleep 1000ms 37 | AsyncLoadTestModel model2 = service.getRemoteModel("two", 1000); // 每个请求sleep 1000ms 38 | AsyncLoadTestModel model3 = service.getRemoteModel("three", 1000); // 每个请求sleep 1000ms 39 | 40 | long start = 0, end = 0; 41 | start = System.currentTimeMillis(); 42 | System.out.println(model1.getDetail()); 43 | end = System.currentTimeMillis(); 44 | Assert.assertTrue((end - start) > 500l); // 第一次会阻塞, 响应时间会在1000ms左右 45 | 46 | start = System.currentTimeMillis(); 47 | System.out.println(model2.getDetail()); 48 | end = System.currentTimeMillis(); 49 | Assert.assertTrue((end - start) < 500l); // 第二次不会阻塞,因为第一个已经阻塞了1000ms 50 | 51 | start = System.currentTimeMillis(); 52 | System.out.println(model3.getDetail()); 53 | end = System.currentTimeMillis(); 54 | Assert.assertTrue((end - start) < 500l); // 第三次不会阻塞,因为第一个已经阻塞了1000ms 55 | 56 | // 销毁executor 57 | executor.destory(); 58 | } 59 | 60 | @Test 61 | public void testProxy_timeout() { 62 | // 初始化config 63 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 100l); // 设置超时时间为300ms 64 | // 初始化executor 65 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 66 | executor.initital(); 67 | // 初始化proxy 68 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 69 | proxy.setService(asyncLoadTestService); 70 | proxy.setConfig(config); 71 | proxy.setExecutor(executor); 72 | 73 | AsyncLoadTestService service = proxy.getProxy(); 74 | AsyncLoadTestModel model1 = service.getRemoteModel("first", 1000); // 每个请求sleep 1000ms 75 | AsyncLoadTestModel model2 = service.getRemoteModel("two", 200); // 每个请求sleep 1000ms 76 | 77 | long start = 0, end = 0; 78 | start = System.currentTimeMillis(); 79 | try { 80 | System.out.println(model1.getDetail()); 81 | Assert.fail(); // 不会走到这一步 82 | } catch (Exception e) { // TimeoutException异常 83 | System.out.println(e); 84 | } 85 | end = System.currentTimeMillis(); 86 | Assert.assertTrue((end - start) < 500l); // 会超时 87 | 88 | start = System.currentTimeMillis(); 89 | try { 90 | System.out.println(model2.getDetail()); 91 | } catch (Exception e) { 92 | Assert.fail(); // 不会走到这一步 93 | } 94 | end = System.currentTimeMillis(); 95 | Assert.assertTrue((end - start) < 500l); // 不会超时 96 | } 97 | 98 | @Test 99 | public void testProxy_block_reject() { 100 | // 初始化config 101 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); // 设置超时时间为300ms 102 | // 初始化executor 103 | AsyncLoadExecutor executor = new AsyncLoadExecutor(8, 2, AsyncLoadExecutor.HandleMode.REJECT); // 设置为拒绝,8个工作线程,2个等待队列 104 | executor.initital(); 105 | // 初始化proxy 106 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 107 | proxy.setService(asyncLoadTestService); 108 | proxy.setConfig(config); 109 | proxy.setExecutor(executor); 110 | 111 | AsyncLoadTestService service = proxy.getProxy(); 112 | ExecutorService executeService = Executors.newFixedThreadPool(10); 113 | long start = 0, end = 0; 114 | start = System.currentTimeMillis(); 115 | try { 116 | for (int i = 0; i < 10; i++) { // 创建10个任务 117 | final AsyncLoadTestModel model = service.getRemoteModel("first:" + i, 1000); // 每个请求sleep 1000ms 118 | executeService.submit(new Runnable() { 119 | 120 | public void run() { 121 | System.out.println(model.getDetail()); 122 | } 123 | }); 124 | } 125 | } catch (RejectedExecutionException e) { // 不会出现reject 126 | Assert.fail(); 127 | } 128 | 129 | try { 130 | final AsyncLoadTestModel model = service.getRemoteModel("first:" + 11, 1000); // 创建第11个任务,会出现reject异常 131 | executeService.submit(new Runnable() { 132 | 133 | public void run() { 134 | System.out.println(model.getDetail()); 135 | } 136 | }); 137 | 138 | Assert.fail();// 不会走到这一步 139 | } catch (RejectedExecutionException e) { 140 | System.out.println(e);// 会出现reject 141 | } 142 | 143 | try { 144 | Thread.sleep(2000l); 145 | } catch (InterruptedException e) { 146 | Assert.fail(); 147 | } 148 | executeService.shutdown(); 149 | end = System.currentTimeMillis(); 150 | System.out.println(end - start); 151 | } 152 | 153 | @Test 154 | public void testProxy_block_reject_noQueue() { 155 | // 初始化config 156 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); // 设置超时时间为3000ms 157 | // 初始化executor 158 | AsyncLoadExecutor executor = new AsyncLoadExecutor(2, 0, AsyncLoadExecutor.HandleMode.REJECT); // 设置为拒绝 159 | executor.initital(); 160 | // 初始化proxy 161 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 162 | proxy.setService(asyncLoadTestService); 163 | proxy.setConfig(config); 164 | proxy.setExecutor(executor); 165 | 166 | AsyncLoadTestService service = proxy.getProxy(); 167 | ExecutorService executeService = Executors.newFixedThreadPool(10); 168 | long start = 0, end = 0; 169 | start = System.currentTimeMillis(); 170 | try { 171 | for (int i = 0; i < 5; i++) { // 创建5个任务 172 | final AsyncLoadTestModel model = service.getRemoteModel("first:" + i, 1000); // 每个请求sleep 1000ms 173 | executeService.submit(new Runnable() { 174 | 175 | public void run() { 176 | System.out.println(model.getDetail()); 177 | } 178 | }); 179 | } 180 | 181 | Assert.fail(); // 不会走到这一步 182 | } catch (RejectedExecutionException e) { // 会出现reject 183 | System.out.println(e);// 会出现reject 184 | } 185 | 186 | try { 187 | Thread.sleep(2000l); 188 | } catch (InterruptedException e) { 189 | Assert.fail(); 190 | } 191 | executeService.shutdown(); 192 | end = System.currentTimeMillis(); 193 | System.out.println(end - start); 194 | } 195 | 196 | @Test 197 | public void testProxy_block_callerRun() { 198 | // 初始化config 199 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); // 设置超时时间为3000ms 200 | // 初始化executor 201 | AsyncLoadExecutor executor = new AsyncLoadExecutor(1, 0, AsyncLoadExecutor.HandleMode.CALLERRUN); // 设置为caller线程运行模式,10个工作线程,0个等待队列 202 | executor.initital(); 203 | // 初始化proxy 204 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 205 | proxy.setService(asyncLoadTestService); 206 | proxy.setConfig(config); 207 | proxy.setExecutor(executor); 208 | 209 | AsyncLoadTestService service = proxy.getProxy(); 210 | ExecutorService executeService = Executors.newFixedThreadPool(2); 211 | long start = 0, end = 0; 212 | start = System.currentTimeMillis(); 213 | try { 214 | for (int i = 0; i < 3; i++) { // 创建10个任务 215 | final AsyncLoadTestModel model = service.getRemoteModel("first:" + i, 1000); // 每个请求sleep 1000ms 216 | executeService.submit(new Runnable() { 217 | 218 | public void run() { 219 | System.out.println(model.getDetail()); 220 | } 221 | }); 222 | } 223 | 224 | Thread.sleep(4000l); 225 | } catch (RejectedExecutionException e) { // 不会出现reject 226 | Assert.fail(); 227 | } catch (InterruptedException e) { 228 | Assert.fail(); 229 | } 230 | 231 | executeService.shutdown(); 232 | end = System.currentTimeMillis(); 233 | System.out.println(end - start); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/AsyncLoadReturnClassTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import java.util.List; 4 | 5 | import javax.annotation.Resource; 6 | 7 | import junit.framework.Assert; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 13 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 14 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 15 | 16 | /** 17 | * 测试对应returnClass不同类型 18 | * 19 | * @author jianghang 2011-2-9 下午11:06:35 20 | */ 21 | public class AsyncLoadReturnClassTest extends BaseAsyncLoadNoRunTest { 22 | 23 | @Resource(name = "asyncLoadTestService") 24 | private AsyncLoadTestService asyncLoadTestService; 25 | private AsyncLoadTestService proxy; 26 | 27 | @Before 28 | public void setUp() { 29 | // 初始化config 30 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 31 | // 初始化executor 32 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 33 | executor.initital(); 34 | // 初始化proxy 35 | AsyncLoadEnhanceProxy proxyFactory = new AsyncLoadEnhanceProxy(); 36 | proxyFactory.setService(asyncLoadTestService); 37 | proxyFactory.setConfig(config); 38 | proxyFactory.setExecutor(executor); 39 | // 执行测试 40 | proxy = proxyFactory.getProxy(); 41 | } 42 | 43 | @Test 44 | public void testClass_ok() { 45 | long start, end; 46 | start = System.currentTimeMillis(); 47 | Object model = proxy.getRemoteModel("first", 1000); 48 | end = System.currentTimeMillis(); 49 | Assert.assertTrue((end - start) < 500l); // 不会阻塞 50 | // 检查对应的返回对象model为AsyncLoadTestModel的子类 51 | Assert.assertTrue(model.getClass().getSuperclass() == AsyncLoadTestModel.class); 52 | System.out.println(model.getClass()); 53 | } 54 | 55 | @Test 56 | public void testClass_primitive() { 57 | long start, end; 58 | start = System.currentTimeMillis(); 59 | int model = proxy.countRemoteModel("first", 1000); 60 | end = System.currentTimeMillis(); 61 | Assert.assertTrue((end - start) > 500l); // 阻塞 62 | System.out.println(model); 63 | } 64 | 65 | @Test 66 | public void testClass_void() { 67 | long start, end; 68 | start = System.currentTimeMillis(); 69 | proxy.updateRemoteModel("first", 1000l); 70 | end = System.currentTimeMillis(); 71 | Assert.assertTrue((end - start) > 500l); // 阻塞 72 | } 73 | 74 | @Test 75 | public void testClass_list() { 76 | long start, end; 77 | start = System.currentTimeMillis(); 78 | Object model = proxy.listRemoteModel("first", 1000l); 79 | end = System.currentTimeMillis(); 80 | Assert.assertTrue((end - start) < 500l); // 不会阻塞 81 | // 检查对应的返回对象model为ArrayList 82 | Assert.assertTrue(model.getClass().getInterfaces()[1] == List.class); 83 | System.out.println(model.getClass()); 84 | } 85 | 86 | @Test 87 | public void testClass_final() { 88 | long start, end; 89 | start = System.currentTimeMillis(); 90 | Object model = proxy.getRemoteName("first", 1000l); 91 | end = System.currentTimeMillis(); 92 | Assert.assertTrue((end - start) > 500l); // 阻塞 93 | // 检查对应的返回对象model为ArrayList 94 | Assert.assertTrue(model.getClass() == String.class); 95 | System.out.println(model.getClass()); 96 | } 97 | 98 | @Test 99 | public void testClass_object() { 100 | long start, end; 101 | start = System.currentTimeMillis(); 102 | Object model = proxy.getRemoteObject("first", 1000l); 103 | end = System.currentTimeMillis(); 104 | Assert.assertTrue((end - start) > 500l); // 阻塞,Object对象不做代理 105 | System.out.println(model); 106 | // 检查对应的返回对象model为Object 107 | Assert.assertTrue(model.getClass().getSuperclass() == Object.class); 108 | System.out.println(model.getClass()); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/AsyncLoadThreadLocalTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import javax.annotation.Resource; 4 | 5 | import junit.framework.Assert; 6 | 7 | import org.junit.Test; 8 | 9 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 10 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 11 | import com.alibaba.asyncload.impl.template.AsyncLoadCallback; 12 | import com.alibaba.asyncload.impl.template.AsyncLoadTemplate; 13 | 14 | /** 15 | * 测试下ThreadLocal继承 16 | * 17 | *
 18 |  * 在异步加载中对ThreadLocal为只读,尽量不对其set操作,有set操作潜在的分析:
 19 |  * 1. 两个并行加载代码块,B依赖A的ThreadLocal设置
 20 |  * 2. 并行加载代码快和caller线程存在ThreadLocal依赖,caller线程依赖其ThreadLocal设置
 21 |  * 3. 两个并行加载代码块,各自设置了自己的ThreadLocal信息,需要在caller线程进行合并
 22 |  * 
23 | * 24 | * @author jianghang 2011-3-28 下午11:00:35 25 | */ 26 | public class AsyncLoadThreadLocalTest extends BaseAsyncLoadNoRunTest { 27 | 28 | @Resource(name = "asyncLoadTemplate") 29 | private AsyncLoadTemplate asyncLoadTemplate; 30 | 31 | @Resource(name = "asyncLoadTestService") 32 | private AsyncLoadTestService asyncLoadTestService; 33 | 34 | private final ThreadLocal threadLocal = new ThreadLocal(); 35 | private final ThreadLocal callerThreadLocal = new ThreadLocal(); 36 | private final ThreadLocal inheritableThreadLocal = new InheritableThreadLocal(); 37 | private final ThreadLocal inheritableCallerThreadLocal = new InheritableThreadLocal(); 38 | 39 | @Test 40 | public void testThreadLocalGet() { 41 | final String name = "testThreadLocal"; 42 | threadLocal.set(name); 43 | AsyncLoadTestModel model = asyncLoadTemplate.execute(new AsyncLoadCallback() { 44 | 45 | public AsyncLoadTestModel doAsyncLoad() { 46 | Assert.assertEquals(threadLocal.get(), name);// 验证threadLocal属性是否和caller Thread设置的一样 47 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 48 | } 49 | }, 2000); 50 | 51 | model.getName();// 阻塞至结果返回 52 | } 53 | 54 | @Test 55 | public void testThreadLocalRunnerSet() { 56 | final String name = "testThreadLocal"; 57 | AsyncLoadTestModel model = asyncLoadTemplate.execute(new AsyncLoadCallback() { 58 | 59 | public AsyncLoadTestModel doAsyncLoad() { 60 | threadLocal.set(name);// 内部设置了threadLocal,外部能直接获取 61 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 62 | } 63 | }, 2000); 64 | model.getName();// 阻塞至结果返回 65 | Assert.assertEquals(threadLocal.get(), name);// 验证threadLocal属性是否和runner Thread设置的一样 66 | } 67 | 68 | @Test 69 | public void testThreadLocalCallerSet() { 70 | final String name = "testThreadLocal"; 71 | callerThreadLocal.set(name + 2); 72 | AsyncLoadTestModel model = asyncLoadTemplate.execute(new AsyncLoadCallback() { 73 | 74 | public AsyncLoadTestModel doAsyncLoad() { 75 | Assert.assertEquals(callerThreadLocal.get(), name + 2);// 验证threadLocal属性是否和caller Thread设置的一样 76 | threadLocal.set(name + 1);// 内部设置了threadLocal,外部能直接获取 77 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 78 | } 79 | }, 2000); 80 | model.getName();// 阻塞至结果返回 81 | Assert.assertEquals(threadLocal.get(), name + 1);// 验证threadLocal属性是否和runner Thread设置的一样 82 | System.out.println(callerThreadLocal.get()); 83 | System.out.println(threadLocal.get()); 84 | } 85 | 86 | @Test 87 | public void testInheritableThreadLocalGet() { 88 | final String name = "testInheritableThreadLocal"; 89 | inheritableThreadLocal.set(name); 90 | AsyncLoadTestModel model = asyncLoadTemplate.execute(new AsyncLoadCallback() { 91 | 92 | public AsyncLoadTestModel doAsyncLoad() { 93 | Assert.assertEquals(inheritableThreadLocal.get(), name);// 验证threadLocal属性是否和caller Thread设置的一样 94 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 95 | } 96 | }, 2000); 97 | 98 | model.getName();// 阻塞至结果返回 99 | } 100 | 101 | @Test 102 | public void testInheritableThreadLocalRunnerSet() { 103 | final String name = "testInheritableThreadLocal"; 104 | AsyncLoadTestModel model = asyncLoadTemplate.execute(new AsyncLoadCallback() { 105 | 106 | public AsyncLoadTestModel doAsyncLoad() { 107 | inheritableThreadLocal.set(name);// 内部设置了threadLocal,外部能直接获取 108 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 109 | } 110 | }, 2000); 111 | model.getName();// 阻塞至结果返回 112 | Assert.assertEquals(inheritableThreadLocal.get(), name);// 验证threadLocal属性是否和runner Thread设置的一样 113 | } 114 | 115 | @Test 116 | public void testInheritableThreadLocalCallerSet() { 117 | final String name = "testInheritableThreadLocal"; 118 | inheritableCallerThreadLocal.set(name + 2); 119 | AsyncLoadTestModel model = asyncLoadTemplate.execute(new AsyncLoadCallback() { 120 | 121 | public AsyncLoadTestModel doAsyncLoad() { 122 | Assert.assertEquals(inheritableCallerThreadLocal.get(), name + 2);// 验证threadLocal属性是否和caller 123 | // Thread设置的一样 124 | inheritableThreadLocal.set(name + 1);// 内部设置了threadLocal,外部能直接获取 125 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 126 | } 127 | }, 2000); 128 | model.getName();// 阻塞至结果返回 129 | Assert.assertEquals(inheritableThreadLocal.get(), name + 1);// 验证threadLocal属性是否和runner Thread设置的一样 130 | System.out.println(inheritableCallerThreadLocal.get()); 131 | System.out.println(inheritableThreadLocal.get()); 132 | } 133 | 134 | @Test 135 | public void testThreadLocalMisc() { 136 | // 处理ThreadLocal和inheritableThreadLocal混合使用,检查是否正确处理数据 137 | final String name = "testThreadLocalMisc"; 138 | inheritableCallerThreadLocal.set(name + 2); 139 | AsyncLoadTestModel model = asyncLoadTemplate.execute(new AsyncLoadCallback() { 140 | 141 | public AsyncLoadTestModel doAsyncLoad() { 142 | Assert.assertEquals(inheritableCallerThreadLocal.get(), name + 2);// 验证threadLocal属性是否和caller 143 | // Thread设置的一样 144 | threadLocal.set(name + 1);// 内部设置了threadLocal,外部能直接获取 145 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 146 | } 147 | }, 2000); 148 | model.getName();// 阻塞至结果返回 149 | Assert.assertEquals(threadLocal.get(), name + 1);// 验证threadLocal属性是否和runner Thread设置的一样 150 | System.out.println(inheritableCallerThreadLocal.get()); 151 | System.out.println(threadLocal.get()); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/BaseAsyncLoadNoRunTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import com.alibaba.asyncload.impl.helper.AsyncLoadProxyRepository; 4 | import junit.framework.Assert; 5 | import org.junit.Before; 6 | import org.junit.Ignore; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.context.ApplicationContextAware; 11 | import org.springframework.test.context.ContextConfiguration; 12 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 13 | 14 | import java.util.concurrent.ConcurrentHashMap; 15 | 16 | //@ContextConfiguration(locations = { "classpath:asyncload/applicationContext.xml" }) 17 | @RunWith(SpringJUnit4ClassRunner.class) 18 | @ContextConfiguration(locations = { 19 | "classpath*:/asyncload/application*.xml"}) 20 | @Ignore 21 | public abstract class BaseAsyncLoadNoRunTest implements ApplicationContextAware { 22 | public ApplicationContext applicationContext; 23 | @Before 24 | public void setUp() { 25 | // System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/tmp/cglib/"); 26 | // 清空repository内的cache记录 27 | try { 28 | TestUtils.setField(new AsyncLoadProxyRepository(), "reponsitory", new ConcurrentHashMap()); 29 | } catch (Exception e) { 30 | Assert.fail(); 31 | } 32 | } 33 | 34 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{ 35 | this.applicationContext = applicationContext; 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/TestUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | 6 | import org.springframework.util.ReflectionUtils; 7 | 8 | /** 9 | * 提供常见的测试方法 10 | * 11 | * @author jianghang 2011-1-30 上午11:15:54 12 | */ 13 | public class TestUtils { 14 | 15 | /** 16 | * 获取对应属性的值 17 | * 18 | * @param obj 19 | * @param fieldName 20 | * @return 21 | */ 22 | public static Object getField(Object obj, String fieldName) { 23 | Field field = ReflectionUtils.findField(obj.getClass(), fieldName); 24 | ReflectionUtils.makeAccessible(field); 25 | return ReflectionUtils.getField(field, obj); 26 | } 27 | 28 | /** 29 | * 设置对应参数的值 30 | * 31 | * @param target 32 | * @param methodName 33 | * @param args 34 | * @return 35 | * @throws Exception 36 | */ 37 | public static void setField(Object target, String fieldName, Object args) throws Exception { 38 | // 查找对应的方法 39 | Field field = ReflectionUtils.findField(target.getClass(), fieldName); 40 | ReflectionUtils.makeAccessible(field); 41 | ReflectionUtils.setField(field, target, args); 42 | } 43 | 44 | /** 45 | * 调用方法,可以是一些私有方法 46 | * 47 | * @param target 48 | * @param methodName 49 | * @param args 50 | * @return 51 | * @throws Exception 52 | */ 53 | public static Object invokeMethod(Object target, String methodName, Object... args) throws Exception { 54 | Method method = null; 55 | // 查找对应的方法 56 | if (args == null || args.length == 0) { 57 | method = ReflectionUtils.findMethod(target.getClass(), methodName); 58 | } else { 59 | Class[] argsClass = new Class[args.length]; 60 | for (int i = 0; i < args.length; i++) { 61 | argsClass[i] = args[i].getClass(); 62 | } 63 | method = ReflectionUtils.findMethod(target.getClass(), methodName, argsClass); 64 | } 65 | ReflectionUtils.makeAccessible(method); 66 | 67 | if (args == null || args.length == 0) { 68 | return ReflectionUtils.invokeMethod(method, target); 69 | } else { 70 | return ReflectionUtils.invokeMethod(method, target, args); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/classinfo/AsyncLoadClassinfoTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.classinfo; 2 | 3 | import java.io.Serializable; 4 | import java.lang.annotation.Annotation; 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.Method; 7 | import java.lang.reflect.Type; 8 | import java.lang.reflect.TypeVariable; 9 | 10 | import org.junit.Assert; 11 | import org.junit.Test; 12 | 13 | import com.alibaba.asyncload.AsyncLoadConfig; 14 | import com.alibaba.asyncload.AsyncLoadExecutor; 15 | import com.alibaba.asyncload.BaseAsyncLoadNoRunTest; 16 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 17 | 18 | /** 19 | * 测试下代理下的annotation,generic,field属性 20 | * 21 | * @author jianghang 2011-4-1 下午11:58:25 22 | */ 23 | public class AsyncLoadClassinfoTest extends BaseAsyncLoadNoRunTest { 24 | 25 | @Test 26 | public void testClassAnnotation_lose() { 27 | ClassInfoService service = getProxy(); 28 | Annotation[] as = service.getClass().getAnnotations(); 29 | Assert.assertEquals(as.length, 1);// 因为设置了Classi为允许继承,所以能获得 30 | } 31 | 32 | @Test 33 | public void testField_notFound() { 34 | ClassInfoService service = getProxy(); 35 | try { 36 | service.getClass().getDeclaredField("ser");// 属性丢失,无法找到 37 | Assert.fail();// 不会走到这一步 38 | } catch (Exception e) { 39 | } 40 | } 41 | 42 | @Test 43 | public void testMethodAnnotation_lose() { 44 | 45 | ClassInfoService service = getProxy(); 46 | try { 47 | Method method = service.getClass().getMethod("test", new Class[] { Object.class }); 48 | Annotation[] as = method.getAnnotations(); 49 | Assert.assertEquals(as.length, 0); 50 | Annotation[][] ass = method.getParameterAnnotations(); 51 | Assert.assertEquals(ass.length, 1);// 有1个参数 52 | Assert.assertEquals(ass[0].length, 0);// 这个参数没有annotation 53 | } catch (Exception e) { 54 | Assert.fail(); 55 | } 56 | 57 | } 58 | 59 | @Test 60 | public void testMethodGeneric_lose() { 61 | ClassInfoService service = getProxy(); 62 | try { 63 | Method setMethod = service.getClass().getMethod("setSer", new Class[] { Serializable.class }); 64 | Type[] parameters = setMethod.getGenericParameterTypes(); 65 | Assert.assertFalse(parameters[0] instanceof TypeVariable); // 不是一个泛型对象 66 | Method getMethod = service.getClass().getMethod("getSer", new Class[] {}); 67 | Type returnType = getMethod.getGenericReturnType(); 68 | Assert.assertFalse(returnType instanceof TypeVariable); // 不是一个泛型对象 69 | } catch (Exception e) { 70 | Assert.fail(); 71 | } 72 | 73 | } 74 | 75 | @Test 76 | public void testSuperClassAnnotation_ok() { 77 | ClassInfoService service = getProxy(); 78 | Annotation[] as = service.getClass().getSuperclass().getAnnotations(); 79 | Assert.assertEquals(as.length, 1);// 因为设置了Classi为允许继承,所以能获得 80 | } 81 | 82 | @Test 83 | public void testSuperFieldAnnotation_ok() { 84 | ClassInfoService service = getProxy(); 85 | try { 86 | Field field = service.getClass().getSuperclass().getDeclaredField("ser");// 属性丢失,无法找到 87 | Annotation[] as = field.getAnnotations(); 88 | Assert.assertEquals(as.length, 1); 89 | } catch (Exception e) { 90 | Assert.fail();// 不会走到这一步 91 | } 92 | } 93 | 94 | @Test 95 | public void testSuperMethodAnnotation_ok() { 96 | 97 | ClassInfoService service = getProxy(); 98 | try { 99 | Method method = service.getClass().getSuperclass().getMethod("test", new Class[] { Object.class }); 100 | Annotation[] as = method.getAnnotations(); 101 | Assert.assertEquals(as.length, 1); 102 | Annotation[][] ass = method.getParameterAnnotations(); 103 | Assert.assertEquals(ass.length, 1);// 有1个参数 104 | Assert.assertEquals(ass[0].length, 1);// 有1个annotation 105 | } catch (Exception e) { 106 | Assert.fail(); 107 | } 108 | 109 | } 110 | 111 | @Test 112 | public void testSuperMethodGeneric_ok() { 113 | ClassInfoService service = getProxy(); 114 | try { 115 | Method setMethod = service.getClass() 116 | .getSuperclass() 117 | .getMethod("setSer", new Class[] { Serializable.class }); 118 | Type[] parameters = setMethod.getGenericParameterTypes(); 119 | Assert.assertTrue(parameters[0] instanceof TypeVariable); // 是一个泛型对象 120 | Method getMethod = service.getClass().getSuperclass().getMethod("getSer", new Class[] {}); 121 | Type returnType = getMethod.getGenericReturnType(); 122 | Assert.assertTrue(returnType instanceof TypeVariable); // 是一个泛型对象 123 | } catch (Exception e) { 124 | Assert.fail(); 125 | } 126 | } 127 | 128 | private ClassInfoService getProxy() { 129 | // 初始化config 130 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 131 | // 初始化executor 132 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 133 | executor.initital(); 134 | // 初始化proxy 135 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 136 | proxy.setService(new ClassInfoService()); 137 | proxy.setConfig(config); 138 | proxy.setExecutor(executor); 139 | return proxy.getProxy(); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/classinfo/ClassInfoService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.classinfo; 2 | 3 | import java.io.Serializable; 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Inherited; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | /** 12 | * @author jianghang 2011-4-1 下午11:49:26 13 | */ 14 | @Classi(value = "class") 15 | public class ClassInfoService { 16 | 17 | @Fieldi(value = "field") 18 | protected O ser; 19 | 20 | @Methodi(value = "method") 21 | public void test(@Parameteri(value = "param") Object param) { 22 | System.out.println("hello"); 23 | } 24 | 25 | public O getSer() { 26 | return ser; 27 | } 28 | 29 | public void setSer(O ser) { 30 | this.ser = ser; 31 | } 32 | 33 | } 34 | 35 | @Documented 36 | @Retention(RetentionPolicy.RUNTIME) 37 | @Target(ElementType.TYPE) 38 | @Inherited 39 | @interface Classi { 40 | 41 | String value(); 42 | } 43 | 44 | @Documented 45 | @Retention(RetentionPolicy.RUNTIME) 46 | @Target(ElementType.FIELD) 47 | @Inherited 48 | @interface Fieldi { 49 | 50 | String value(); 51 | } 52 | 53 | @Documented 54 | @Retention(RetentionPolicy.RUNTIME) 55 | @Target(ElementType.METHOD) 56 | @Inherited 57 | @interface Methodi { 58 | 59 | String value(); 60 | } 61 | 62 | @Documented 63 | @Retention(RetentionPolicy.RUNTIME) 64 | @Target(ElementType.PARAMETER) 65 | @Inherited 66 | @interface Parameteri { 67 | 68 | String value(); 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/classinfo/JavassistClassinfoTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.classinfo; 2 | 3 | import com.alibaba.asyncload.BaseAsyncLoadNoRunTest; 4 | import com.alibaba.asyncload.impl.helper.AsyncLoadReflectionHelper; 5 | import javassist.util.proxy.MethodHandler; 6 | import javassist.util.proxy.ProxyFactory; 7 | import javassist.util.proxy.ProxyObject; 8 | import net.sf.cglib.reflect.FastMethod; 9 | import org.junit.Test; 10 | 11 | import java.lang.reflect.Method; 12 | 13 | /** 14 | * @author jianghang 2011-4-2 下午01:54:16 15 | */ 16 | public class JavassistClassinfoTest extends BaseAsyncLoadNoRunTest { 17 | 18 | @Test 19 | public void test() throws Exception { 20 | ProxyFactory proxyFactory = new ProxyFactory(); 21 | proxyFactory.setSuperclass(ClassInfoService.class); 22 | Class proxyClass = proxyFactory.createClass(); 23 | ClassInfoService javassistProxy = (ClassInfoService) proxyClass.newInstance(); 24 | ((ProxyObject) javassistProxy).setHandler(new JavaAssitInterceptor(new ClassInfoService())); 25 | 26 | javassistProxy.test(new Object()); 27 | 28 | FastMethod fm = AsyncLoadReflectionHelper.getMethod(javassistProxy.getClass(), "test", 29 | new Class[] { Object.class }); 30 | System.out.println(fm.getJavaMethod().getAnnotations().length); 31 | } 32 | 33 | private static class JavaAssitInterceptor implements MethodHandler { 34 | 35 | final Object delegate; 36 | 37 | JavaAssitInterceptor(Object delegate){ 38 | this.delegate = delegate; 39 | } 40 | 41 | public Object invoke(Object self, Method m, Method proceed, Object[] args) throws Throwable { 42 | return m.invoke(delegate, args); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/domain/AsyncLoadTestModel.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.domain; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 一个asyncLoad的测试对象model,返回的对象 7 | * 8 | * @author jianghang 2011-1-21 下午10:45:41 9 | */ 10 | public class AsyncLoadTestModel implements Serializable { 11 | 12 | private static final long serialVersionUID = -5410019316926096126L; 13 | 14 | public AsyncLoadTestModel(int id, String name, String detail){ 15 | this.id = id; 16 | this.name = name; 17 | this.detail = detail; 18 | } 19 | 20 | public int id; 21 | public String name; 22 | public String detail; 23 | 24 | public int getId() { 25 | return id; 26 | } 27 | 28 | public void setId(int id) { 29 | this.id = id; 30 | } 31 | 32 | public String getName() { 33 | return name; 34 | } 35 | 36 | public void setName(String name) { 37 | this.name = name; 38 | } 39 | 40 | public String getDetail() { 41 | return detail; 42 | } 43 | 44 | public void setDetail(String detail) { 45 | this.detail = detail; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "AsyncLoadTestModel [detail=" + detail + ", id=" + id + ", name=" + name + "]"; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/domain/AsyncLoadTestService.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.domain; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 一个asyncLoad的测试对象服务 7 | * 8 | * @author jianghang 2011-1-21 下午10:45:19 9 | */ 10 | public interface AsyncLoadTestService { 11 | 12 | public int countRemoteModel(String name, long sleep); 13 | 14 | public void updateRemoteModel(String name, long slepp); 15 | 16 | public AsyncLoadTestModel getRemoteModel(String name, long sleep); 17 | 18 | public String getRemoteName(String name, long sleep); 19 | 20 | public Object getRemoteObject(String name, long sleep); 21 | 22 | public List listRemoteModel(String name, long sleep); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/domain/AsyncLoadTestServiceDAO.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.domain; 2 | 3 | /** 4 | * @author jianghang 2011-1-21 下午10:46:19 5 | */ 6 | public class AsyncLoadTestServiceDAO { 7 | 8 | public void doSleep(long sleep) { 9 | try { 10 | Thread.sleep(sleep); // 睡一下 11 | } catch (InterruptedException e) { 12 | e.printStackTrace(); 13 | } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/domain/AsyncLoadTestServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.domain; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 一个测试AsyncLoad的默认实现 8 | * 9 | * @author jianghang 2011-1-21 下午10:46:19 10 | */ 11 | public class AsyncLoadTestServiceImpl implements AsyncLoadTestService { 12 | 13 | private AsyncLoadTestServiceDAO asyncLoadTestServiceDAO; 14 | 15 | public AsyncLoadTestModel getRemoteModel(String name, long sleep) { 16 | if (sleep > 0) { 17 | asyncLoadTestServiceDAO.doSleep(sleep); 18 | } 19 | AsyncLoadTestModel model = new AsyncLoadTestModel(1, name, name); 20 | return model; 21 | } 22 | 23 | public List listRemoteModel(String name, long sleep) { 24 | List models = new ArrayList(); 25 | for (int i = 0; i < 2; i++) { 26 | if (sleep > 0) { 27 | asyncLoadTestServiceDAO.doSleep(sleep); 28 | } 29 | AsyncLoadTestModel model = new AsyncLoadTestModel(1, name, name); 30 | models.add(model); 31 | } 32 | return models; 33 | } 34 | 35 | public int countRemoteModel(String name, long sleep) { 36 | if (sleep > 0) { 37 | asyncLoadTestServiceDAO.doSleep(sleep); 38 | } 39 | return 0; 40 | } 41 | 42 | public void updateRemoteModel(String name, long sleep) { 43 | if (sleep > 0) { 44 | asyncLoadTestServiceDAO.doSleep(sleep); 45 | } 46 | } 47 | 48 | public String getRemoteName(String name, long sleep) { 49 | if (sleep > 0) { 50 | asyncLoadTestServiceDAO.doSleep(sleep); 51 | } 52 | return name; 53 | } 54 | 55 | public Object getRemoteObject(String name, long sleep) { 56 | if (sleep > 0) { 57 | asyncLoadTestServiceDAO.doSleep(sleep); 58 | } 59 | return name; 60 | } 61 | 62 | public void setAsyncLoadTestServiceDAO(AsyncLoadTestServiceDAO asyncLoadTestServiceDAO) { 63 | this.asyncLoadTestServiceDAO = asyncLoadTestServiceDAO; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/helper/AsyncLoadReflectionHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.helper; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import com.alibaba.asyncload.impl.helper.AsyncLoadReflectionHelper; 7 | 8 | /** 9 | * @author jianghang 2011-3-31 下午02:34:00 10 | */ 11 | public class AsyncLoadReflectionHelperTest { 12 | 13 | @Test 14 | public void testDefaultValue_primitive() { 15 | // 原型对象数组 16 | Assert.assertArrayEquals((Object[]) AsyncLoadReflectionHelper.getDefaultValue(Boolean[].class), 17 | new Boolean[] {}); 18 | Assert.assertArrayEquals((Object[]) AsyncLoadReflectionHelper.getDefaultValue(Byte[].class), new Byte[] {}); 19 | Assert.assertArrayEquals((Object[]) AsyncLoadReflectionHelper.getDefaultValue(Character[].class), 20 | new Character[] {}); 21 | Assert.assertArrayEquals((Object[]) AsyncLoadReflectionHelper.getDefaultValue(Short[].class), new Short[] {}); 22 | Assert.assertArrayEquals((Object[]) AsyncLoadReflectionHelper.getDefaultValue(Double[].class), new Double[] {}); 23 | Assert.assertArrayEquals((Object[]) AsyncLoadReflectionHelper.getDefaultValue(Float[].class), new Float[] {}); 24 | Assert.assertArrayEquals((Object[]) AsyncLoadReflectionHelper.getDefaultValue(Integer[].class), 25 | new Integer[] {}); 26 | Assert.assertArrayEquals((Object[]) AsyncLoadReflectionHelper.getDefaultValue(Long[].class), new Long[] {}); 27 | // 原型数组 28 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(boolean[].class).getClass(), boolean[].class); 29 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(byte[].class).getClass(), byte[].class); 30 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(char[].class).getClass(), char[].class); 31 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(short[].class).getClass(), short[].class); 32 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(double[].class).getClass(), double[].class); 33 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(float[].class).getClass(), float[].class); 34 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(int[].class).getClass(), int[].class); 35 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(long[].class).getClass(), long[].class); 36 | // 原型 37 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(boolean.class), false); 38 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(byte.class), (byte) 0); 39 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(char.class), (char) 0); 40 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(short.class), (short) 0); 41 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(double.class), (double) 0); 42 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(float.class), (float) 0); 43 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(int.class), (int) 0); 44 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(long.class), (long) 0); 45 | // 原型对应的对象 46 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(Boolean.class), Boolean.FALSE); 47 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(Byte.class), (byte) 0); 48 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(Character.class), (char) 0); 49 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(Short.class), (short) 0); 50 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(Double.class), (double) 0); 51 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(Float.class), (float) 0); 52 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(Integer.class), (int) 0); 53 | Assert.assertEquals(AsyncLoadReflectionHelper.getDefaultValue(Long.class), (long) 0); 54 | } 55 | 56 | @Test 57 | public void testNewInstance() { 58 | DefaultValueObjectB objectb = (DefaultValueObjectB) AsyncLoadReflectionHelper.newInstance(DefaultValueObjectB.class); 59 | Assert.assertEquals(objectb.a, 0); 60 | Assert.assertArrayEquals(objectb.arr, new Integer[] {}); 61 | 62 | // 递归对象创建 63 | DefaultValueObjectA objecta = (DefaultValueObjectA) AsyncLoadReflectionHelper.newInstance(DefaultValueObjectA.class); 64 | Assert.assertEquals(objecta.a, 0); 65 | Assert.assertArrayEquals(objecta.arr, new Integer[] {}); 66 | // Assert.assertEquals(objecta.b, null); 67 | Assert.assertEquals(objecta.b.a, 0); 68 | Assert.assertArrayEquals(objecta.b.arr, new Integer[] {}); 69 | 70 | } 71 | } 72 | 73 | class DefaultValueObjectA { 74 | 75 | public int a; 76 | public Integer[] arr; 77 | public DefaultValueObjectB b; 78 | 79 | public DefaultValueObjectA(int a, Integer[] arr, DefaultValueObjectB b){ 80 | this.a = a; 81 | this.arr = arr; 82 | this.b = b; 83 | } 84 | } 85 | 86 | class DefaultValueObjectB { 87 | 88 | public int a; 89 | public Integer[] arr; 90 | 91 | public DefaultValueObjectB(int a, Integer[] arr){ 92 | this.a = a; 93 | this.arr = arr; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/spring/AsyncLoadFactoryBeanTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.spring; 2 | 3 | import java.util.List; 4 | 5 | import javax.annotation.Resource; 6 | 7 | import junit.framework.Assert; 8 | 9 | import org.junit.Test; 10 | 11 | import com.alibaba.asyncload.BaseAsyncLoadNoRunTest; 12 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 13 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 14 | 15 | /** 16 | * @author jianghang 2011-1-29 下午06:06:29 17 | */ 18 | public class AsyncLoadFactoryBeanTest extends BaseAsyncLoadNoRunTest { 19 | 20 | @Resource(name = "asyncLoadTestFactoryBean") 21 | private AsyncLoadTestService asyncLoadTestFactoryBean; 22 | 23 | @Test 24 | public void testFactoryBean() { 25 | AsyncLoadTestModel model1 = asyncLoadTestFactoryBean.getRemoteModel("first", 1000); 26 | AsyncLoadTestModel model2 = asyncLoadTestFactoryBean.getRemoteModel("two", 1000); 27 | long start = 0, end = 0; 28 | start = System.currentTimeMillis(); 29 | System.out.println(model1.getDetail()); 30 | end = System.currentTimeMillis(); 31 | Assert.assertTrue((end - start) > 500l); // 第一次会阻塞, 响应时间会在1000ms左右 32 | 33 | start = System.currentTimeMillis(); 34 | System.out.println(model2.getDetail()); 35 | end = System.currentTimeMillis(); 36 | Assert.assertTrue((end - start) < 500l); // 第二次不会阻塞,第一个已经阻塞了1000ms 37 | 38 | long model3_start = System.currentTimeMillis(); 39 | AsyncLoadTestModel model3 = asyncLoadTestFactoryBean.getRemoteModel("three", 1000); 40 | List model4 = asyncLoadTestFactoryBean.listRemoteModel("three", 1000); 41 | 42 | start = System.currentTimeMillis(); 43 | System.out.println(model3.getDetail()); 44 | end = System.currentTimeMillis(); 45 | Assert.assertTrue((end - start) < 1500l); // 不会阻塞,因为list已经阻塞了1000ms 46 | 47 | System.out.println(model4.get(0)); 48 | Assert.assertTrue((System.currentTimeMillis() - model3_start) > 1500l); // 因为被排除list不走asyncLoad,所以时间是近2000ms 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/spring/AsyncLoadSpringCompsiteTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.spring; 2 | 3 | import javax.annotation.Resource; 4 | 5 | import junit.framework.Assert; 6 | 7 | import org.junit.Test; 8 | 9 | import com.alibaba.asyncload.BaseAsyncLoadNoRunTest; 10 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 11 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 12 | 13 | /** 14 | * @author jianghang 2011-4-25 下午03:17:39 15 | */ 16 | public class AsyncLoadSpringCompsiteTest extends BaseAsyncLoadNoRunTest { 17 | 18 | @Resource(name = "asyncLoadTestServiceForCompsitePrototype") 19 | private AsyncLoadTestService asyncLoadTestServiceForCompsitePrototype; 20 | 21 | @Resource(name = "asyncLoadTestServiceForCompsiteSingleton") 22 | private AsyncLoadTestService asyncLoadTestServiceForCompsiteSingleton; 23 | 24 | @Resource(name = "asyncLoadTestServiceForCompsiteFactoryBean") 25 | private AsyncLoadTestService asyncLoadTestServiceForCompsiteFactoryBean; 26 | 27 | @Test 28 | public void testPrototype() { 29 | internalTest(asyncLoadTestServiceForCompsitePrototype); 30 | AsyncLoadTestService service = (AsyncLoadTestService) this.applicationContext.getBean("asyncLoadTestServiceForCompsitePrototype"); 31 | Assert.assertNotSame(service, asyncLoadTestServiceForCompsitePrototype); 32 | } 33 | 34 | @Test 35 | public void testSingleton() { 36 | internalTest(asyncLoadTestServiceForCompsiteSingleton); 37 | AsyncLoadTestService service = (AsyncLoadTestService) this.applicationContext.getBean("asyncLoadTestServiceForCompsiteSingleton"); 38 | Assert.assertSame(service, asyncLoadTestServiceForCompsiteSingleton); 39 | } 40 | 41 | @Test 42 | public void testProxyFactoryBean() { 43 | internalTest(asyncLoadTestServiceForCompsiteFactoryBean); 44 | AsyncLoadTestService service = (AsyncLoadTestService) this.applicationContext.getBean("asyncLoadTestServiceForCompsiteFactoryBean"); 45 | Assert.assertNotSame(service, asyncLoadTestServiceForCompsiteFactoryBean); 46 | } 47 | 48 | private void internalTest(AsyncLoadTestService service) { 49 | AsyncLoadTestModel model1 = service.getRemoteModel("first", 1000); 50 | AsyncLoadTestModel model2 = service.getRemoteModel("two", 1000); 51 | long start = 0, end = 0; 52 | start = System.currentTimeMillis(); 53 | System.out.println(model1.getDetail()); 54 | end = System.currentTimeMillis(); 55 | Assert.assertTrue((end - start) > 500l); // 第一次会阻塞, 响应时间会在1000ms左右 56 | 57 | start = System.currentTimeMillis(); 58 | System.out.println(model2.getDetail()); 59 | end = System.currentTimeMillis(); 60 | Assert.assertTrue((end - start) < 500l); // 第二次不会阻塞,第一个已经阻塞了1000ms 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/spring/AsyncLoadSpringInteceptorTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.spring; 2 | 3 | import javax.annotation.Resource; 4 | 5 | import junit.framework.Assert; 6 | 7 | import org.junit.Test; 8 | 9 | import com.alibaba.asyncload.BaseAsyncLoadNoRunTest; 10 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 11 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 12 | 13 | /** 14 | * 测试一下基于spring拦截器配置的并行加载 15 | * 16 | * @author jianghang 2011-4-1 下午05:16:15 17 | */ 18 | public class AsyncLoadSpringInteceptorTest extends BaseAsyncLoadNoRunTest { 19 | 20 | @Resource(name = "asyncLoadTestServiceForInteceptor") 21 | private AsyncLoadTestService asyncLoadTestServiceForInteceptor; 22 | 23 | @Test 24 | public void testSpringInteceptor() { 25 | AsyncLoadTestModel model1 = asyncLoadTestServiceForInteceptor.getRemoteModel("first", 1000); 26 | AsyncLoadTestModel model2 = asyncLoadTestServiceForInteceptor.getRemoteModel("two", 1000); 27 | long start = 0, end = 0; 28 | start = System.currentTimeMillis(); 29 | System.out.println(model1.getDetail()); 30 | end = System.currentTimeMillis(); 31 | Assert.assertTrue((end - start) > 500l); // 第一次会阻塞, 响应时间会在1000ms左右 32 | 33 | start = System.currentTimeMillis(); 34 | System.out.println(model2.getDetail()); 35 | end = System.currentTimeMillis(); 36 | Assert.assertTrue((end - start) < 500l); // 第二次不会阻塞,第一个已经阻塞了1000ms 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/spring/LogInteceptor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.spring; 2 | 3 | import org.aopalliance.intercept.MethodInterceptor; 4 | import org.aopalliance.intercept.MethodInvocation; 5 | 6 | /** 7 | * @author jianghang 2011-4-25 下午03:14:42 8 | */ 9 | public class LogInteceptor implements MethodInterceptor { 10 | 11 | public Object invoke(MethodInvocation invocation) throws Throwable { 12 | try { 13 | System.out.println("start invoke:" + invocation.getMethod().getName()); 14 | return invocation.proceed(); 15 | } finally { 16 | System.out.println("end invoke:" + invocation.getMethod().getName()); 17 | } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/template/AsyncLoadTemplateTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.template; 2 | 3 | import javax.annotation.Resource; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | import com.alibaba.asyncload.BaseAsyncLoadNoRunTest; 9 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 10 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 11 | import com.alibaba.asyncload.impl.template.AsyncLoadCallback; 12 | import com.alibaba.asyncload.impl.template.AsyncLoadTemplate; 13 | 14 | /** 15 | * @author jianghang 2011-1-29 下午07:13:12 16 | */ 17 | public class AsyncLoadTemplateTest extends BaseAsyncLoadNoRunTest { 18 | 19 | @Resource(name = "asyncLoadTemplate") 20 | private AsyncLoadTemplate asyncLoadTemplate; 21 | 22 | @Resource(name = "asyncLoadTestService") 23 | private AsyncLoadTestService asyncLoadTestService; 24 | 25 | @Test 26 | public void testTemplate() { 27 | 28 | long start = 0, end = 0; 29 | start = System.currentTimeMillis(); 30 | 31 | AsyncLoadTestModel model1 = asyncLoadTestService.getRemoteModel("ljhtest", 1000); 32 | System.out.println(model1.getDetail()); 33 | end = System.currentTimeMillis(); 34 | System.out.println(end - start); 35 | Assert.assertTrue((end - start) > 500l); // 第一次会阻塞, 响应时间会在1000ms左右 36 | Assert.assertTrue((end - start) < 1500l); 37 | 38 | start = System.currentTimeMillis(); 39 | AsyncLoadTestModel model2 = asyncLoadTemplate.execute(new AsyncLoadCallback() { 40 | 41 | public AsyncLoadTestModel doAsyncLoad() { 42 | // 总共sleep 2000ms 43 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 44 | } 45 | }); 46 | asyncLoadTestService.getRemoteModel("ljhtest", 1000); 47 | 48 | System.out.println(model2.getDetail()); 49 | end = System.currentTimeMillis(); 50 | System.out.println(end - start); 51 | Assert.assertTrue((end - start) > 500l); // 只会阻塞一次 1000ms 52 | Assert.assertTrue((end - start) < 1500l); 53 | } 54 | 55 | @Test 56 | public void testTemplate_returnClass() { 57 | 58 | long start = 0, end = 0; 59 | start = System.currentTimeMillis(); 60 | AsyncLoadTestModel model2 = (AsyncLoadTestModel) asyncLoadTemplate.execute(new AsyncLoadCallback() { 61 | 62 | public Object doAsyncLoad() { 63 | // 总共sleep 1000ms 64 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 65 | } 66 | }, AsyncLoadTestModel.class); // 这里指定了返回目标class 67 | asyncLoadTestService.getRemoteModel("ljhtest", 1000); 68 | 69 | System.out.println(model2.getDetail()); 70 | end = System.currentTimeMillis(); 71 | System.out.println(end - start); 72 | Assert.assertTrue((end - start) > 500l); // 只会阻塞一次 1000ms 73 | Assert.assertTrue((end - start) < 1500l); 74 | } 75 | 76 | @Test 77 | public void testTemplate_noGeneric() { 78 | // 没有指定返回对象,会抛异常 79 | try { 80 | asyncLoadTemplate.execute(new AsyncLoadCallback() { 81 | 82 | public Object doAsyncLoad() { 83 | // 总共sleep 2000ms 84 | return asyncLoadTestService.getRemoteModel("ljhtest", 1000); 85 | } 86 | }); 87 | 88 | Assert.fail();// 不会执行到这一步 89 | } catch (Exception e) { 90 | 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/util/AsyncLoadBarrierTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2004 Alibaba.com All right reserved. This software is the confidential and proprietary information of 3 | * Alibaba.com ("Confidential Information"). You shall not disclose such Confidential Information and shall use it only 4 | * in accordance with the terms of the license agreement you entered into with Alibaba.com. 5 | */ 6 | package com.alibaba.asyncload.util; 7 | 8 | import javax.annotation.Resource; 9 | 10 | import junit.framework.Assert; 11 | 12 | import org.junit.Test; 13 | 14 | import com.alibaba.asyncload.AsyncLoadConfig; 15 | import com.alibaba.asyncload.AsyncLoadExecutor; 16 | import com.alibaba.asyncload.BaseAsyncLoadNoRunTest; 17 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 18 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 19 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 20 | import com.alibaba.asyncload.impl.template.AsyncLoadCallback; 21 | import com.alibaba.asyncload.impl.template.AsyncLoadTemplate; 22 | import com.alibaba.asyncload.impl.util.AsyncLoadBarrier; 23 | 24 | /** 25 | * @author jianghang 2011-4-27 下午04:22:42 26 | */ 27 | public class AsyncLoadBarrierTest extends BaseAsyncLoadNoRunTest { 28 | 29 | @Resource(name = "asyncLoadTestService") 30 | private AsyncLoadTestService asyncLoadTestService; 31 | 32 | @Resource(name = "asyncLoadTemplate") 33 | private AsyncLoadTemplate asyncLoadTemplate; 34 | 35 | @Test 36 | public void testTemplateBarrier() { 37 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 38 | config.setNeedBarrierSupport(true); // 39 | 40 | long start = 0, end = 0; 41 | start = System.currentTimeMillis(); 42 | AsyncLoadTestModel model1 = null; 43 | AsyncLoadTestModel model2 = null; 44 | AsyncLoadTestModel model3 = null; 45 | try { 46 | model1 = asyncLoadTemplate.execute(new AsyncLoadCallback() { 47 | 48 | public AsyncLoadTestModel doAsyncLoad() { 49 | return asyncLoadTestService.getRemoteModel("first", 1000); 50 | } 51 | }, config); 52 | 53 | model2 = asyncLoadTemplate.execute(new AsyncLoadCallback() { 54 | 55 | public AsyncLoadTestModel doAsyncLoad() { 56 | return asyncLoadTestService.getRemoteModel("two", 1000); 57 | } 58 | }, config); 59 | 60 | model3 = asyncLoadTemplate.execute(new AsyncLoadCallback() { 61 | 62 | public AsyncLoadTestModel doAsyncLoad() { 63 | return asyncLoadTestService.getRemoteModel("three", 1000); 64 | } 65 | }, config); 66 | } finally { 67 | AsyncLoadBarrier.await(); 68 | end = System.currentTimeMillis(); 69 | Assert.assertTrue((end - start) > 500l); // barrier会阻塞等待所有的线程返回, 响应时间会在1000ms左右 70 | start = System.currentTimeMillis(); 71 | model1.getDetail(); 72 | model2.getDetail(); 73 | model3.getDetail(); 74 | end = System.currentTimeMillis(); 75 | Assert.assertTrue((end - start) < 500l); // barrier后的都不会进行阻塞 76 | 77 | } 78 | } 79 | 80 | @Test 81 | public void testTemplateNoBarrier() { 82 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 83 | config.setNeedBarrierSupport(false); // 84 | 85 | long start = 0, end = 0; 86 | start = System.currentTimeMillis(); 87 | AsyncLoadTestModel model1 = null; 88 | AsyncLoadTestModel model2 = null; 89 | AsyncLoadTestModel model3 = null; 90 | try { 91 | model1 = asyncLoadTemplate.execute(new AsyncLoadCallback() { 92 | 93 | public AsyncLoadTestModel doAsyncLoad() { 94 | return asyncLoadTestService.getRemoteModel("first", 1000); 95 | } 96 | }, config); 97 | 98 | model2 = asyncLoadTemplate.execute(new AsyncLoadCallback() { 99 | 100 | public AsyncLoadTestModel doAsyncLoad() { 101 | return asyncLoadTestService.getRemoteModel("two", 1000); 102 | } 103 | }, config); 104 | 105 | model3 = asyncLoadTemplate.execute(new AsyncLoadCallback() { 106 | 107 | public AsyncLoadTestModel doAsyncLoad() { 108 | return asyncLoadTestService.getRemoteModel("three", 1000); 109 | } 110 | }, config); 111 | } finally { 112 | AsyncLoadBarrier.await(); 113 | end = System.currentTimeMillis(); 114 | Assert.assertTrue((end - start) < 500l); // 没有barrier,就不会阻塞 115 | start = System.currentTimeMillis(); 116 | model1.getDetail(); 117 | model2.getDetail(); 118 | model3.getDetail(); 119 | end = System.currentTimeMillis(); 120 | Assert.assertTrue((end - start) > 500l); // 进行阻塞 121 | 122 | } 123 | } 124 | 125 | @Test 126 | public void testBarrier() { 127 | // 初始化config 128 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 129 | config.setNeedBarrierSupport(true); // 130 | // 初始化executor 131 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 132 | executor.initital(); 133 | // 初始化proxy 134 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 135 | proxy.setService(asyncLoadTestService); 136 | proxy.setConfig(config); 137 | proxy.setExecutor(executor); 138 | // 执行测试 139 | long start, end; 140 | start = System.currentTimeMillis(); 141 | AsyncLoadTestModel model1 = null; 142 | AsyncLoadTestModel model2 = null; 143 | AsyncLoadTestModel model3 = null; 144 | 145 | try { 146 | AsyncLoadTestService service = proxy.getProxy(); 147 | model1 = service.getRemoteModel("first", 1000); // 每个请求sleep 1000ms 148 | model2 = service.getRemoteModel("two", 1000); // 每个请求sleep 1000ms 149 | model3 = service.getRemoteModel("three", 1000); // 每个请求sleep 1000ms 150 | 151 | } finally { 152 | AsyncLoadBarrier.await(); 153 | end = System.currentTimeMillis(); 154 | Assert.assertTrue((end - start) > 500l); // barrier会阻塞等待所有的线程返回, 响应时间会在1000ms左右 155 | start = System.currentTimeMillis(); 156 | model1.getDetail(); 157 | model2.getDetail(); 158 | model3.getDetail(); 159 | end = System.currentTimeMillis(); 160 | Assert.assertTrue((end - start) < 500l); // barrier后的都不会进行阻塞 161 | 162 | // 销毁executor 163 | executor.destory(); 164 | } 165 | 166 | } 167 | 168 | @Test 169 | public void testNoBarrier() { 170 | // 初始化config 171 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 172 | config.setNeedBarrierSupport(true); // 173 | // 初始化executor 174 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 175 | executor.initital(); 176 | // 初始化proxy 177 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 178 | proxy.setService(asyncLoadTestService); 179 | proxy.setConfig(config); 180 | proxy.setExecutor(executor); 181 | // 执行测试 182 | long start, end; 183 | start = System.currentTimeMillis(); 184 | AsyncLoadTestModel model1 = null; 185 | AsyncLoadTestModel model2 = null; 186 | AsyncLoadTestModel model3 = null; 187 | 188 | try { 189 | AsyncLoadTestService service = proxy.getProxy(); 190 | model1 = service.getRemoteModel("first", 1000); // 每个请求sleep 1000ms 191 | model2 = service.getRemoteModel("two", 1000); // 每个请求sleep 1000ms 192 | model3 = service.getRemoteModel("three", 1000); // 每个请求sleep 1000ms 193 | 194 | } finally { 195 | // AsyncLoadBarrier.await(); 196 | end = System.currentTimeMillis(); 197 | Assert.assertTrue((end - start) < 500l); // 没有barrier,就不会阻塞 198 | start = System.currentTimeMillis(); 199 | model1.getDetail(); 200 | model2.getDetail(); 201 | model3.getDetail(); 202 | end = System.currentTimeMillis(); 203 | Assert.assertTrue((end - start) > 500l); // 阻塞调用 204 | 205 | // 销毁executor 206 | executor.destory(); 207 | } 208 | 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/util/AsyncLoadUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import javax.annotation.Resource; 7 | 8 | import junit.framework.Assert; 9 | 10 | import org.junit.Test; 11 | 12 | import com.alibaba.asyncload.AsyncLoadConfig; 13 | import com.alibaba.asyncload.AsyncLoadExecutor; 14 | import com.alibaba.asyncload.BaseAsyncLoadNoRunTest; 15 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 16 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 17 | import com.alibaba.asyncload.domain.AsyncLoadTestServiceImpl; 18 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 19 | import com.alibaba.asyncload.impl.AsyncLoadStatus; 20 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 21 | import com.alibaba.asyncload.impl.util.AsyncLoadUtils; 22 | 23 | /** 24 | * 获取并行加载的内部数据测试 25 | * 26 | * @author jianghang 2011-4-4 下午06:34:37 27 | */ 28 | public class AsyncLoadUtilsTest extends BaseAsyncLoadNoRunTest { 29 | 30 | @Resource(name = "asyncLoadTestService") 31 | private AsyncLoadTestService asyncLoadTestService; 32 | 33 | @Test 34 | public void testIsNull_true() { 35 | // 初始化config 36 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 37 | // 初始化executor 38 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 39 | executor.initital(); 40 | // 初始化proxy 41 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 42 | proxy.setService(new AsyncLoadTestServiceNullImpl()); 43 | proxy.setConfig(config); 44 | proxy.setExecutor(executor); 45 | AsyncLoadTestService service = proxy.getProxy(); 46 | 47 | AsyncLoadTestModel model = service.getRemoteModel("one", 1000); // 方法直接返回了null 48 | long start = System.currentTimeMillis(); 49 | boolean isNull1 = AsyncLoadUtils.isNull(model); 50 | long end = System.currentTimeMillis(); 51 | Assert.assertTrue(end - start > 500);// 调用这个方法会阻塞 52 | Assert.assertTrue(isNull1); 53 | } 54 | 55 | @Test 56 | public void testIsNull_false() { 57 | // 初始化config 58 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 59 | // 初始化executor 60 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 61 | executor.initital(); 62 | // 初始化proxy 63 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 64 | proxy.setService(new AsyncLoadTestServiceNullImpl()); 65 | proxy.setConfig(config); 66 | proxy.setExecutor(executor); 67 | AsyncLoadTestService service = proxy.getProxy(); 68 | 69 | List models = service.listRemoteModel("one", 1000); // 调用list方法,设置返回了为一个空数组 70 | boolean isNull2 = AsyncLoadUtils.isNull(models); 71 | Assert.assertFalse(isNull2); 72 | if (isNull2 == false) { // 如果不为空,可以调用其内部方法 73 | Assert.assertTrue(models.size() >= 0); 74 | } 75 | } 76 | 77 | @Test 78 | public void testGetOriginalClass() { 79 | // 初始化config 80 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 81 | // 初始化executor 82 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 83 | executor.initital(); 84 | // 初始化proxy 85 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 86 | proxy.setService(asyncLoadTestService); 87 | proxy.setConfig(config); 88 | proxy.setExecutor(executor); 89 | AsyncLoadTestService service = proxy.getProxy(); 90 | 91 | AsyncLoadTestModel model = service.getRemoteModel("one", 1000); // 方法直接返回了null 92 | List models = service.listRemoteModel("one", 1000); // 调用list方法,设置返回了为一个空数组 93 | 94 | long start = System.currentTimeMillis(); 95 | Assert.assertEquals(AsyncLoadUtils.getOriginalClass(model), AsyncLoadTestModel.class);// 是个具体子类 96 | Assert.assertEquals(AsyncLoadUtils.getOriginalClass(models), List.class);// 是个接口 97 | long end = System.currentTimeMillis(); 98 | Assert.assertTrue(end - start < 500);// 调用这个方法不会进行阻塞 99 | } 100 | 101 | @Test 102 | public void testGetOriginalResult() { 103 | // 初始化config 104 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 105 | // 初始化executor 106 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 107 | executor.initital(); 108 | // 初始化proxy 109 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 110 | proxy.setService(asyncLoadTestService); 111 | proxy.setConfig(config); 112 | proxy.setExecutor(executor); 113 | AsyncLoadTestService service = proxy.getProxy(); 114 | 115 | AsyncLoadTestModel model = service.getRemoteModel("one", 1000); // 方法直接返回了null 116 | List models = service.listRemoteModel("one", 1000); // 调用list方法,设置返回了为一个空数组 117 | 118 | long start = System.currentTimeMillis(); 119 | Assert.assertEquals(AsyncLoadUtils.getOriginalResult(model).getClass(), AsyncLoadTestModel.class);// 是个具体子类 120 | Assert.assertEquals(AsyncLoadUtils.getOriginalResult(models).getClass(), ArrayList.class);// 真实返回的是个ArrayList 121 | long end = System.currentTimeMillis(); 122 | Assert.assertTrue(end - start > 500);// 调用这个方法会进行阻塞 123 | } 124 | 125 | @Test 126 | public void testGetStatus_Done() { 127 | // 初始化config 128 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 129 | // 初始化executor 130 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 131 | executor.initital(); 132 | // 初始化proxy 133 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 134 | proxy.setService(asyncLoadTestService); 135 | proxy.setConfig(config); 136 | proxy.setExecutor(executor); 137 | AsyncLoadTestService service = proxy.getProxy(); 138 | 139 | AsyncLoadTestModel model = service.getRemoteModel("one", 1000); 140 | if (AsyncLoadUtils.isNull(model) == false) { 141 | AsyncLoadStatus status = AsyncLoadUtils.getStatus(model); // 获取对应的status 142 | Assert.assertTrue(status.getStatus().isDone()); 143 | Assert.assertTrue(status.getCostTime() > 500 && status.getCostTime() < 1500); 144 | } 145 | 146 | } 147 | 148 | @Test 149 | public void testGetStatus_Timeout() { 150 | // 初始化config 151 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 152 | // 初始化executor 153 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 154 | executor.initital(); 155 | // 初始化proxy 156 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 157 | proxy.setService(asyncLoadTestService); 158 | proxy.setConfig(config); 159 | proxy.setExecutor(executor); 160 | AsyncLoadTestService service = proxy.getProxy(); 161 | 162 | AsyncLoadTestModel model = null; 163 | try { 164 | model = service.getRemoteModel("one", 4000); 165 | } catch (AsyncLoadException e) { 166 | } 167 | try { 168 | AsyncLoadUtils.isNull(model); 169 | Assert.fail(); 170 | } catch (Exception e) { 171 | // 因为超时了,所以会出现Timeout异常 172 | } 173 | AsyncLoadStatus status = AsyncLoadUtils.getStatus(model); // 获取对应的status 174 | Assert.assertTrue(status.getStatus().isTimeout()); 175 | Assert.assertTrue(status.getCostTime() > 2500 && status.getCostTime() < 3500); 176 | 177 | } 178 | 179 | @Test 180 | public void testGetStatus_Run() { 181 | // 初始化config 182 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 183 | // 初始化executor 184 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 185 | executor.initital(); 186 | // 初始化proxy 187 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 188 | proxy.setService(asyncLoadTestService); 189 | proxy.setConfig(config); 190 | proxy.setExecutor(executor); 191 | AsyncLoadTestService service = proxy.getProxy(); 192 | final AsyncLoadTestModel model = service.getRemoteModel("one", 2000); 193 | 194 | try { 195 | Thread.sleep(1000); 196 | } catch (InterruptedException e) { 197 | Assert.fail(); 198 | } 199 | 200 | Thread t = new Thread() { 201 | 202 | public void run() { 203 | long start = System.currentTimeMillis(); 204 | AsyncLoadStatus status = AsyncLoadUtils.getStatus(model); // 获取对应的status 205 | Assert.assertTrue(status.getStatus().isRun()); 206 | Assert.assertTrue(status.getCostTime() > 500 && status.getCostTime() < 1500); // 当前运行了1000ms左右 207 | long end = System.currentTimeMillis(); 208 | Assert.assertTrue(end - start < 500);// 调用这个方法不会进行阻塞 209 | } 210 | }; 211 | t.start(); 212 | } 213 | 214 | public static class AsyncLoadTestServiceNullImpl extends AsyncLoadTestServiceImpl { 215 | 216 | @Override 217 | public AsyncLoadTestModel getRemoteModel(String name, long sleep) { 218 | try { 219 | Thread.sleep(sleep); 220 | } catch (InterruptedException e) { 221 | } 222 | return null; // 直接mock为空 223 | } 224 | 225 | @Override 226 | public List listRemoteModel(String name, long sleep) { 227 | try { 228 | Thread.sleep(sleep); 229 | } catch (InterruptedException e) { 230 | } 231 | return new ArrayList(); 232 | } 233 | } 234 | 235 | } 236 | -------------------------------------------------------------------------------- /src/test/resources/asyncload/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | (.*)RemoteModel(.*) 16 | 17 | 18 | 19 | 20 | (.*)listRemoteModel(.*) 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | asyncLoadTestServiceForInteceptor 60 | 61 | 62 | 63 | 64 | asyncLoadInterceptor 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | logInteceptor 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | asyncLoadTestServiceForCompsitePrototype 90 | asyncLoadTestServiceForCompsiteSingleton 91 | asyncLoadTestServiceForCompsiteFactoryBean 92 | 93 | 94 | 95 | 96 | asyncLoadInterceptor 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | asyncLoadTestServiceForCompsitePrototype 106 | asyncLoadTestServiceForCompsiteSingleton 107 | asyncLoadTestServiceForCompsiteFactoryBean 108 | 109 | 110 | 111 | 112 | logInteceptor 113 | 114 | 115 | 116 | 117 | --------------------------------------------------------------------------------