├── .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 | nas上文件 (共享文件存储)
13 | output/xxx (磁盘文件)
14 | memcache client / cat client (cache服务)
15 | database (oracle , mysql) (数据库)
16 | dubbo client (外部服务)
17 | search client (搜索引擎)
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 |
--------------------------------------------------------------------------------