├── .gitignore ├── src ├── main │ ├── java │ │ └── com │ │ │ └── alibaba │ │ │ └── asyncload │ │ │ ├── impl │ │ │ ├── template │ │ │ │ ├── AsyncLoadCallback.java │ │ │ │ └── AsyncLoadTemplate.java │ │ │ ├── pool │ │ │ │ ├── AsyncLoadCallable.java │ │ │ │ ├── NamedThreadFactory.java │ │ │ │ ├── AsyncLoadFuture.java │ │ │ │ └── AsyncLoadThreadPool.java │ │ │ ├── enums │ │ │ │ └── PoolRejectHandleMode.java │ │ │ ├── annotation │ │ │ │ ├── AsyncLoadAnnotationConstants.java │ │ │ │ ├── EnableAsyncMethod.java │ │ │ │ ├── EnableAsyncClass.java │ │ │ │ ├── AsyncLoadAnnotationThreadLocal.java │ │ │ │ ├── AsyncClassDef.java │ │ │ │ ├── EnableAsyncClassMethodInfo.java │ │ │ │ ├── AsyncThreadPoolConfig.java │ │ │ │ ├── AsyncEnableAnnotationParserFactory.java │ │ │ │ ├── AsyncMethodDef.java │ │ │ │ ├── AsyncLoadHandlerAdvice.java │ │ │ │ ├── AsyncLoadEnableAdvice.java │ │ │ │ ├── AsyncLoadHandleFactory.java │ │ │ │ └── AsyncAnnotationParserFactory.java │ │ │ ├── exceptions │ │ │ │ └── AsyncLoadException.java │ │ │ ├── AsyncLoadService.java │ │ │ ├── AsyncLoadObject.java │ │ │ ├── helper │ │ │ │ ├── AsyncLoadProxyRepository.java │ │ │ │ └── AsyncLoadReflectionHelper.java │ │ │ ├── AsyncLoadStatus.java │ │ │ ├── util │ │ │ │ ├── MethodFilterUtil.java │ │ │ │ ├── AsyncLoadBarrier.java │ │ │ │ └── AsyncLoadUtils.java │ │ │ ├── spring │ │ │ │ ├── AsyncLoadFactoryBean.java │ │ │ │ ├── AsyncLoadInterceptor.java │ │ │ │ └── CompositeAutoProxyCreator.java │ │ │ ├── AsyncLoadPerl5RegexpMethodMatcher.java │ │ │ ├── AsyncLoadResult.java │ │ │ └── AsyncLoadEnhanceProxy.java │ │ │ ├── AsyncLoadMethodMatch.java │ │ │ ├── AsyncLoadProxy.java │ │ │ ├── AsyncLoadConfig.java │ │ │ └── AsyncLoadExecutor.java │ └── resources │ │ └── bean-asyncload-sample.xml └── test │ ├── java │ └── com │ │ └── alibaba │ │ └── asyncload │ │ ├── domain │ │ ├── AsyncLoadTestServiceDAO.java │ │ ├── AsyncLoadTestService.java │ │ ├── AsyncLoadTestModel.java │ │ └── AsyncLoadTestServiceImpl.java │ │ ├── annotation │ │ ├── AsyncThreadLocalInheriteTest.java │ │ ├── AsyncLoadAnnotationMultiTest.java │ │ ├── AsyncLoadAnnotationMultiMethodTest.java │ │ ├── AsyncLoadAnnotationTest.java │ │ └── AsyncLoadAnnotationTestServiceImpl.java │ │ ├── spring │ │ ├── LogInteceptor.java │ │ ├── AsyncLoadSpringInteceptorTest.java │ │ ├── AsyncLoadFactoryBeanTest.java │ │ └── AsyncLoadSpringCompsiteTest.java │ │ ├── classinfo │ │ ├── ClassInfoService.java │ │ ├── JavassistClassinfoTest.java │ │ └── AsyncLoadClassinfoTest.java │ │ ├── BaseAsyncLoadNoRunTest.java │ │ ├── AsyncLoadExecutorTest.java │ │ ├── TestUtils.java │ │ ├── AsyncLoadFinalClassTest.java │ │ ├── template │ │ └── AsyncLoadTemplateTest.java │ │ ├── AsyncLoadMethodMatchTest.java │ │ ├── AsyncLoadReturnClassTest.java │ │ ├── helper │ │ └── AsyncLoadReflectionHelperTest.java │ │ ├── AsyncLoadThreadLocalTest.java │ │ ├── util │ │ ├── AsyncLoadBarrierTest.java │ │ └── AsyncLoadUtilsTest.java │ │ └── AsyncLoadProxyTest.java │ └── resources │ └── asyncload │ └── applicationContext.xml ├── README.md └── pom.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 | -------------------------------------------------------------------------------- /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/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/enums/PoolRejectHandleMode.java: -------------------------------------------------------------------------------- 1 | /** 2 | * HandleMode.java 3 | * author: yujiakui 4 | * 2018年4月17日 5 | * 下午3:47:33 6 | */ 7 | package com.alibaba.asyncload.impl.enums; 8 | 9 | /** 10 | * @author yujiakui 11 | * 12 | * 下午3:47:33 13 | * 14 | * 线程池队列满了之后对应的处理模式 15 | * 16 | */ 17 | public enum PoolRejectHandleMode { 18 | /** 线程池队列满了之后再来请求直接拒绝 */ 19 | REJECT, 20 | /** 用于被拒绝任务的处理程序,它直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务 */ 21 | CALLERRUN; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/annotation/AsyncLoadAnnotationConstants.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadAnnotationConstants.java 3 | * author: yujiakui 4 | * 2018年4月20日 5 | * 下午3:24:22 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | /** 10 | * @author yujiakui 11 | * 12 | * 下午3:24:22 13 | * 14 | * 异步并行注解常量 15 | * 16 | */ 17 | public interface AsyncLoadAnnotationConstants { 18 | 19 | /** 通用类名 */ 20 | String ALL_CLASSES = "ALL_CLASSES"; 21 | 22 | /** 所有的方法 */ 23 | String ALL_METHODS = ".*"; 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/domain/AsyncLoadTestServiceDAO.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.asyncload.domain; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | /** 6 | * @author jianghang 2011-1-21 下午10:46:19 7 | */ 8 | @Component 9 | public class AsyncLoadTestServiceDAO { 10 | 11 | public void doSleep(long sleep) { 12 | try { 13 | System.out.println("----------sleep---------"); 14 | Thread.sleep(sleep); // 睡一下 15 | System.out.println("-----------sleep end---------"); 16 | } catch (InterruptedException e) { 17 | e.printStackTrace(); 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/annotation/AsyncThreadLocalInheriteTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncThreadLocalInheriteTest.java 3 | * author: yujiakui 4 | * 2018年4月23日 5 | * 上午9:20:39 6 | */ 7 | package com.alibaba.asyncload.annotation; 8 | 9 | /** 10 | * @author yujiakui 11 | * 12 | * 上午9:20:39 13 | * 14 | */ 15 | public class AsyncThreadLocalInheriteTest { 16 | 17 | private final static ThreadLocal threadLocal = new ThreadLocal(); 18 | 19 | public static void set(String cnt) { 20 | threadLocal.set(cnt); 21 | } 22 | 23 | public static String get() { 24 | return threadLocal.get(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /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/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 Integer 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/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/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/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/annotation/EnableAsyncMethod.java: -------------------------------------------------------------------------------- 1 | /** 2 | * EnableAsyncMethod.java 3 | * author: yujiakui 4 | * 2018年4月20日 5 | * 下午3:54:02 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | import java.lang.annotation.Documented; 13 | import java.lang.annotation.Retention; 14 | import java.lang.annotation.Target; 15 | 16 | @Documented 17 | @Retention(RUNTIME) 18 | @Target(METHOD) 19 | /** 20 | * @author yujiakui 21 | * 22 | * 下午3:54:02 23 | * 24 | */ 25 | public @interface EnableAsyncMethod { 26 | 27 | /** 28 | * 异步并行类方法信息列表 29 | * 30 | * @return 31 | */ 32 | EnableAsyncClassMethodInfo[] classMethodInfos() default { @EnableAsyncClassMethodInfo }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/annotation/EnableAsyncClass.java: -------------------------------------------------------------------------------- 1 | /** 2 | * EnableAsyncClass.java 3 | * author: yujiakui 4 | * 2018年4月19日 5 | * 上午11:35:46 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import static java.lang.annotation.ElementType.TYPE; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | import java.lang.annotation.Documented; 13 | import java.lang.annotation.Inherited; 14 | import java.lang.annotation.Retention; 15 | import java.lang.annotation.Target; 16 | 17 | @Documented 18 | @Retention(RUNTIME) 19 | @Target({ TYPE }) 20 | @Inherited 21 | /** 22 | * @author yujiakui 23 | * 24 | * 上午11:35:46 25 | * 26 | */ 27 | public @interface EnableAsyncClass { 28 | 29 | /** 30 | * 异步并行类方法信息列表 31 | * 32 | * @return 33 | */ 34 | EnableAsyncClassMethodInfo[] classMethodInfos() default { @EnableAsyncClassMethodInfo }; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/annotation/AsyncLoadAnnotationThreadLocal.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadAnnotationThreadLocal.java 3 | * author: yujiakui 4 | * 2018年4月20日 5 | * 下午2:56:51 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | * @author yujiakui 13 | * 14 | * 下午2:56:51 15 | * 16 | */ 17 | public class AsyncLoadAnnotationThreadLocal { 18 | 19 | /** 异步并行加载map,其中key对应的classFullName,String[]对应的是方法签名匹配表达式 */ 20 | private static final ThreadLocal> asyncLoadMapThreadLocal = new ThreadLocal<>(); 21 | 22 | public static void setAsyncLoadMap(Map asyncLoadMap) { 23 | asyncLoadMapThreadLocal.set(asyncLoadMap); 24 | } 25 | 26 | public static Map getAsyncLoadMap() { 27 | return asyncLoadMapThreadLocal.get(); 28 | } 29 | 30 | public static void removeAsyncLoadMap() { 31 | asyncLoadMapThreadLocal.remove(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/annotation/AsyncClassDef.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncClass.java 3 | * author: yujiakui 4 | * 2018年4月17日 5 | * 下午3:06:31 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import static java.lang.annotation.ElementType.TYPE; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | import java.lang.annotation.Documented; 13 | import java.lang.annotation.Inherited; 14 | import java.lang.annotation.Retention; 15 | import java.lang.annotation.Target; 16 | 17 | @Documented 18 | @Retention(RUNTIME) 19 | @Target({ TYPE }) 20 | @Inherited 21 | /** 22 | * @author yujiakui 23 | * 24 | * 下午3:06:31 25 | * 26 | */ 27 | public @interface AsyncClassDef { 28 | 29 | /** 30 | * 异步方法列表 31 | * 32 | * @return 33 | */ 34 | AsyncMethodDef[] asyncMethods() default {}; 35 | 36 | /** 37 | * 类级别线程池配置 38 | * 39 | * @return 40 | */ 41 | AsyncThreadPoolConfig classThreadPoolConf() default @AsyncThreadPoolConfig; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /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/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/annotation/EnableAsyncClassMethodInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * EnableAsyncClassMethodInfo.java 3 | * author: yujiakui 4 | * 2018年4月19日 5 | * 上午11:44:26 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import static java.lang.annotation.ElementType.TYPE_USE; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | import java.lang.annotation.Documented; 13 | import java.lang.annotation.Retention; 14 | import java.lang.annotation.Target; 15 | 16 | @Documented 17 | @Retention(RUNTIME) 18 | @Target(TYPE_USE) 19 | /** 20 | * @author yujiakui 21 | * 22 | * 上午11:44:26 23 | * 24 | * 开启异步并行类方法信息 25 | */ 26 | public @interface EnableAsyncClassMethodInfo { 27 | 28 | /** 29 | * 对应类的全名,默认是ALL,就是全部(即是标记了异步并行定义的类) 30 | * 31 | * @return 32 | */ 33 | String classFullName() default AsyncLoadAnnotationConstants.ALL_CLASSES; 34 | 35 | /** 36 | * 默认全部标记定义了所有异步并行加载的方法 37 | * 38 | * @return 39 | */ 40 | String[] methodMatchRegex() default { AsyncLoadAnnotationConstants.ALL_METHODS }; 41 | } 42 | -------------------------------------------------------------------------------- /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/annotation/AsyncThreadPoolConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncThreadPoolConfig.java 3 | * author: yujiakui 4 | * 2018年4月17日 5 | * 下午3:43:29 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 10 | 11 | import java.lang.annotation.Documented; 12 | import java.lang.annotation.ElementType; 13 | import java.lang.annotation.Retention; 14 | import java.lang.annotation.Target; 15 | 16 | import com.alibaba.asyncload.impl.enums.PoolRejectHandleMode; 17 | 18 | @Documented 19 | @Retention(RUNTIME) 20 | @Target({ ElementType.ANNOTATION_TYPE }) 21 | /** 22 | * @author yujiakui 23 | * 24 | * 下午3:43:29 25 | * 26 | * 异步线程池配置 27 | */ 28 | public @interface AsyncThreadPoolConfig { 29 | 30 | /** 31 | * 是否生效,默认为不生效(如果方法上的线程池不生效,则找类上面的,如果类上面的也不生效,则只有默认全局的) 32 | * 33 | * @return 34 | */ 35 | boolean effect() default false; 36 | 37 | /** 38 | * 线程池核心线程数和最大线程数的大小,默认是20 39 | * 40 | * @return 41 | */ 42 | int poolSize() default 20; 43 | 44 | /** 45 | * 队列大小,默认是100 46 | * 47 | * @return 48 | */ 49 | int queueSize() default 100; 50 | 51 | /** 52 | * 线程池拒绝处理策略 53 | * 54 | * @return 55 | */ 56 | PoolRejectHandleMode rejectPolicy() default PoolRejectHandleMode.CALLERRUN; 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/annotation/AsyncEnableAnnotationParserFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncEnableAnnotationParserFactory.java 3 | * author: yujiakui 4 | * 2018年4月19日 5 | * 下午1:56:02 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import org.springframework.beans.BeansException; 10 | import org.springframework.beans.factory.InitializingBean; 11 | import org.springframework.context.ApplicationContext; 12 | import org.springframework.context.ApplicationContextAware; 13 | 14 | /** 15 | * @author yujiakui 16 | * 17 | * 下午1:56:02 18 | * 19 | * 异步开启注解解析器工厂 20 | */ 21 | public class AsyncEnableAnnotationParserFactory 22 | implements ApplicationContextAware, InitializingBean { 23 | 24 | /* (non-Javadoc) 25 | * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() 26 | */ 27 | @Override 28 | public void afterPropertiesSet() throws Exception { 29 | // TODO Auto-generated method stub 30 | 31 | } 32 | 33 | /* (non-Javadoc) 34 | * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) 35 | */ 36 | @Override 37 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 38 | // TODO Auto-generated method stub 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /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/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/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/main/java/com/alibaba/asyncload/impl/annotation/AsyncMethodDef.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncMethod.java 3 | * author: yujiakui 4 | * 2018年4月17日 5 | * 下午3:02:52 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import static java.lang.annotation.ElementType.METHOD; 10 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 11 | 12 | import java.lang.annotation.Documented; 13 | import java.lang.annotation.ElementType; 14 | import java.lang.annotation.Retention; 15 | import java.lang.annotation.Target; 16 | 17 | @Documented 18 | @Retention(RUNTIME) 19 | @Target({ METHOD, ElementType.ANNOTATION_TYPE }) 20 | /** 21 | * @author yujiakui 22 | * 23 | * 下午3:02:52 24 | * 25 | * 异步并行方法对应的注解 26 | * 27 | */ 28 | public @interface AsyncMethodDef { 29 | 30 | /** 31 | * 方法匹配对应的正则PatternMatchUtils 32 | * 33 | * 注意:将这个注解放在方法上则这个对应的methodMatchRegex将不起作用,因为此时就是对应这个方法 34 | * 35 | * @return 36 | */ 37 | String[] methodMatchRegex() default {}; 38 | 39 | /** 40 | * 排除方法匹配模式 41 | * 42 | * 注意:将这个注解放在方法上则这个对应的methodMatchRegex将不起作用,因为此时就是对应这个方法 43 | * 44 | * @return 45 | */ 46 | String[] excludeMethodMatchRegex() default {}; 47 | 48 | /** 49 | * 默认超时时间 50 | * 51 | * @return 52 | */ 53 | long timeout() default 1000; 54 | 55 | /** 56 | * 开启的异步线程池中的对应执行的线程是否继承当前线程的threadLocal,默认不继承 57 | * 58 | * @return 59 | */ 60 | boolean inheritThreadLocal() default false; 61 | 62 | /** 63 | * 方法线程池配置 64 | * 65 | * @return 66 | */ 67 | AsyncThreadPoolConfig methodThreadPoolConf() default @AsyncThreadPoolConfig; 68 | 69 | } 70 | -------------------------------------------------------------------------------- /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/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/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/annotation/AsyncLoadAnnotationMultiTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadAnnotationMultiTest.java 3 | * author: yujiakui 4 | * 2018年4月20日 5 | * 下午3:32:12 6 | */ 7 | package com.alibaba.asyncload.annotation; 8 | 9 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 10 | 11 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 12 | 13 | /** 14 | * @author yujiakui 15 | * 16 | * 下午3:32:12 17 | * 18 | */ 19 | public class AsyncLoadAnnotationMultiTest { 20 | 21 | public static void main(String[] args) { 22 | AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext( 23 | "com.alibaba.asyncload.impl.annotation", "com.alibaba.asyncload.annotation", 24 | "com.alibaba.asyncload.domain"); 25 | System.out.println(annotationConfigApplicationContext.getBeanDefinitionNames()); 26 | 27 | /*AsyncLoadHandlerAop aop = annotationConfigApplicationContext 28 | .getBean(AsyncLoadHandlerAop.class);*/ 29 | 30 | // 执行测试 31 | AsyncLoadAnnotationMultiMethodTest service = annotationConfigApplicationContext 32 | .getBean(AsyncLoadAnnotationMultiMethodTest.class); 33 | Thread current = Thread.currentThread(); 34 | 35 | AsyncThreadLocalInheriteTest.set("yjk----test"); 36 | System.out.println("线程信息:" + current); 37 | AsyncLoadTestModel model = service.multiHandler("xxx", 1000); 38 | System.out.println(model); 39 | long start = 0, end = 0; 40 | start = System.currentTimeMillis(); 41 | System.out.println(model.getDetail()); 42 | end = System.currentTimeMillis(); 43 | System.out.println("costTime:" + (end - start)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /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/util/MethodFilterUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MethodFilterUtil.java 3 | * author: yujiakui 4 | * 2018年4月17日 5 | * 下午6:19:06 6 | */ 7 | package com.alibaba.asyncload.impl.util; 8 | 9 | import java.lang.reflect.Method; 10 | import java.util.List; 11 | 12 | import org.aspectj.lang.ProceedingJoinPoint; 13 | import org.aspectj.lang.Signature; 14 | import org.aspectj.lang.reflect.MethodSignature; 15 | 16 | import com.google.common.collect.Lists; 17 | 18 | /** 19 | * @author yujiakui 20 | * 21 | * 下午6:19:06 22 | * 23 | */ 24 | public class MethodFilterUtil { 25 | 26 | /** 过滤的方法列表 */ 27 | public static final List excludeFilterMethods = Lists.newArrayList(); 28 | 29 | static { 30 | excludeFilterMethods.add("wait"); 31 | excludeFilterMethods.add("equals"); 32 | excludeFilterMethods.add("toString"); 33 | excludeFilterMethods.add("hashCode"); 34 | excludeFilterMethods.add("getClass"); 35 | excludeFilterMethods.add("notify"); 36 | excludeFilterMethods.add("notifyAll"); 37 | } 38 | 39 | /** 40 | * 对方法进行过滤,返回true表示不用处理,直接过滤掉 41 | * 42 | * @param method 43 | * @return 44 | */ 45 | public static boolean filterMethod(Method method) { 46 | if (excludeFilterMethods.contains(method.getName())) { 47 | return true; 48 | } else { 49 | return false; 50 | } 51 | } 52 | 53 | /** 54 | * 对方法进行过滤,返回true表示不用处理,直接过滤掉 55 | * 56 | * @param method 57 | * @return 58 | */ 59 | public static boolean filterMethod(ProceedingJoinPoint pjp) { 60 | Signature signature = pjp.getSignature(); 61 | MethodSignature methodSignature = (MethodSignature) signature; 62 | Method method = methodSignature.getMethod(); 63 | return filterMethod(method); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /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/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/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/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 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | /** 9 | * 一个测试AsyncLoad的默认实现 10 | * 11 | * @author jianghang 2011-1-21 下午10:46:19 12 | */ 13 | public class AsyncLoadTestServiceImpl implements AsyncLoadTestService { 14 | 15 | @Autowired 16 | private AsyncLoadTestServiceDAO asyncLoadTestServiceDAO; 17 | 18 | @Override 19 | public AsyncLoadTestModel getRemoteModel(String name, long sleep) { 20 | if (sleep > 0) { 21 | asyncLoadTestServiceDAO.doSleep(sleep); 22 | } 23 | AsyncLoadTestModel model = new AsyncLoadTestModel(1, name, name); 24 | return model; 25 | } 26 | 27 | @Override 28 | public List listRemoteModel(String name, long sleep) { 29 | List models = new ArrayList(); 30 | for (int i = 0; i < 2; i++) { 31 | if (sleep > 0) { 32 | asyncLoadTestServiceDAO.doSleep(sleep); 33 | } 34 | AsyncLoadTestModel model = new AsyncLoadTestModel(1, name, name); 35 | models.add(model); 36 | } 37 | return models; 38 | } 39 | 40 | @Override 41 | public Integer countRemoteModel(String name, long sleep) { 42 | if (sleep > 0) { 43 | asyncLoadTestServiceDAO.doSleep(sleep); 44 | } 45 | return 0; 46 | } 47 | 48 | @Override 49 | public void updateRemoteModel(String name, long sleep) { 50 | if (sleep > 0) { 51 | asyncLoadTestServiceDAO.doSleep(sleep); 52 | } 53 | } 54 | 55 | @Override 56 | public String getRemoteName(String name, long sleep) { 57 | if (sleep > 0) { 58 | asyncLoadTestServiceDAO.doSleep(sleep); 59 | } 60 | return name; 61 | } 62 | 63 | @Override 64 | public Object getRemoteObject(String name, long sleep) { 65 | if (sleep > 0) { 66 | asyncLoadTestServiceDAO.doSleep(sleep); 67 | } 68 | return name; 69 | } 70 | 71 | public void setAsyncLoadTestServiceDAO(AsyncLoadTestServiceDAO asyncLoadTestServiceDAO) { 72 | this.asyncLoadTestServiceDAO = asyncLoadTestServiceDAO; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /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/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/test/java/com/alibaba/asyncload/annotation/AsyncLoadAnnotationMultiMethodTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadAnnotationMultiMethodTest.java 3 | * author: yujiakui 4 | * 2018年4月20日 5 | * 下午3:22:25 6 | */ 7 | package com.alibaba.asyncload.annotation; 8 | 9 | import java.util.List; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 15 | import com.alibaba.asyncload.impl.annotation.EnableAsyncClass; 16 | import com.alibaba.asyncload.impl.annotation.EnableAsyncClassMethodInfo; 17 | import com.alibaba.asyncload.impl.annotation.EnableAsyncMethod; 18 | import com.google.common.collect.Lists; 19 | 20 | /** 21 | * @author yujiakui 22 | * 23 | * 下午3:22:25 24 | * 25 | */ 26 | @Component 27 | @EnableAsyncClass( 28 | classMethodInfos = { @EnableAsyncClassMethodInfo(methodMatchRegex = { ".*count.*" }) }) 29 | public class AsyncLoadAnnotationMultiMethodTest { 30 | 31 | @Autowired 32 | private AsyncLoadAnnotationTestServiceImpl asyncLoadAnnotationTestServiceImpl; 33 | 34 | @EnableAsyncMethod(classMethodInfos = { 35 | @EnableAsyncClassMethodInfo(methodMatchRegex = { "(.*)getRemoteModel(.*)" }) }) 36 | public AsyncLoadTestModel multiHandler(String name, long sleep) { 37 | 38 | List results = Lists.newArrayList(); 39 | for (int i = 0; i < 5; i++) { 40 | AsyncLoadTestModel model = asyncLoadAnnotationTestServiceImpl.getRemoteModel(name, 41 | sleep); 42 | 43 | results.add(model); 44 | model = asyncLoadAnnotationTestServiceImpl.getRemoteModel1(name, sleep); 45 | System.out.println("--------------------" + i + "---------------"); 46 | } 47 | // AsyncLoadTestModel model = 48 | // asyncLoadAnnotationTestServiceImpl.getRemoteModel(name, sleep); 49 | // AsyncLoadTestModel model2 = 50 | // asyncLoadAnnotationTestServiceImpl.getRemoteModel(name, sleep); 51 | 52 | // Integer num = 53 | // asyncLoadAnnotationTestServiceImpl.countRemoteModel(name, sleep); 54 | System.out.println("-------------here---------"); 55 | System.out.println(results.get(0).getDetail()); 56 | // System.out.println(num); 57 | System.out.println("===================="); 58 | return results.get(0); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /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/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/annotation/AsyncLoadAnnotationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadAnnotationTest.java 3 | * author: yujiakui 4 | * 2018年4月18日 5 | * 下午3:25:33 6 | */ 7 | package com.alibaba.asyncload.annotation; 8 | 9 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 10 | 11 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 12 | 13 | import junit.framework.Assert; 14 | 15 | /** 16 | * @author yujiakui 17 | * 18 | * 下午3:25:33 19 | * 20 | */ 21 | public class AsyncLoadAnnotationTest { 22 | 23 | public static void main(String[] args) { 24 | AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext( 25 | "com.alibaba.asyncload.impl.annotation", "com.alibaba.asyncload.annotation", 26 | "com.alibaba.asyncload.domain"); 27 | System.out.println(annotationConfigApplicationContext.getBeanDefinitionNames()); 28 | 29 | /*AsyncLoadHandlerAop aop = annotationConfigApplicationContext 30 | .getBean(AsyncLoadHandlerAop.class);*/ 31 | 32 | // 执行测试 33 | AsyncLoadAnnotationTestServiceImpl service = annotationConfigApplicationContext 34 | .getBean(AsyncLoadAnnotationTestServiceImpl.class); 35 | AsyncLoadTestModel model1 = service.getRemoteModel("first", 1000); // 每个请求sleep 36 | // 1000ms 37 | AsyncLoadTestModel model2 = service.getRemoteModel("two", 1000); // 每个请求sleep 38 | // 1000ms 39 | AsyncLoadTestModel model3 = service.getRemoteModel("three", 1000); // 每个请求sleep 40 | // 1000ms 41 | 42 | long start = 0, end = 0; 43 | start = System.currentTimeMillis(); 44 | System.out.println(model1.getDetail()); 45 | end = System.currentTimeMillis(); 46 | System.out.println("costTime:" + (end - start)); 47 | Assert.assertTrue((end - start) > 500l); // 第一次会阻塞, 响应时间会在1000ms左右 48 | 49 | start = System.currentTimeMillis(); 50 | System.out.println(model2.getDetail()); 51 | end = System.currentTimeMillis(); 52 | System.out.println("costTime:" + (end - start)); 53 | Assert.assertTrue((end - start) < 500l); // 第二次不会阻塞,因为第一个已经阻塞了1000ms 54 | 55 | start = System.currentTimeMillis(); 56 | System.out.println(model3.getDetail()); 57 | end = System.currentTimeMillis(); 58 | System.out.println("costTime:" + (end - start)); 59 | Assert.assertTrue((end - start) < 500l); // 第三次不会阻塞,因为第一个已经阻塞了1000ms 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 对应的设计文档参见:https://www.jianshu.com/p/92c6f402b543 3 | 4 |

背景

5 | 6 |

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

7 | 8 |

9 |

I/O

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

思路

24 | 25 |

26 |

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

27 | 28 |

项目介绍

29 |

名称:asyncload

30 |

译意: async cocurrent load

31 |

语言: 纯java开发

32 |

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

33 |

34 | 35 |

工作原理

36 |


37 |

原理描述:

38 |

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

39 |

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

40 |

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

41 | 42 |

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

43 | 44 |

相关文档

45 | 46 | See the wiki page for : wiki文档 47 | 48 |
49 | wiki文档列表 50 | 57 | 58 |

59 |

问题反馈

60 |

1. qq交流群: 161559791

61 |

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

62 |

3. 新浪微博: agapple0002

63 |

4. 报告issue:issues

64 | -------------------------------------------------------------------------------- /src/test/java/com/alibaba/asyncload/annotation/AsyncLoadAnnotationTestServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadAnnotationTestServiceImpl.java 3 | * author: yujiakui 4 | * 2018年4月18日 5 | * 下午3:29:50 6 | */ 7 | package com.alibaba.asyncload.annotation; 8 | 9 | import java.util.List; 10 | 11 | import org.springframework.stereotype.Component; 12 | 13 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 14 | import com.alibaba.asyncload.domain.AsyncLoadTestServiceImpl; 15 | import com.alibaba.asyncload.impl.annotation.AsyncClassDef; 16 | import com.alibaba.asyncload.impl.annotation.AsyncMethodDef; 17 | import com.alibaba.asyncload.impl.annotation.AsyncThreadPoolConfig; 18 | 19 | /** 20 | * @author yujiakui 21 | * 22 | * 下午3:29:50 23 | * 24 | */ 25 | @Component 26 | @AsyncClassDef( 27 | classThreadPoolConf = @AsyncThreadPoolConfig(effect = true, poolSize = 2, queueSize = 1)) 28 | public class AsyncLoadAnnotationTestServiceImpl extends AsyncLoadTestServiceImpl { 29 | 30 | @Override 31 | @AsyncMethodDef(timeout = 10) 32 | public AsyncLoadTestModel getRemoteModel(String name, long sleep) { 33 | System.out.println( 34 | "-----getRemoteModel-----threadLocal----" + AsyncThreadLocalInheriteTest.get()); 35 | Thread current = Thread.currentThread(); 36 | System.out.println("线程信息:" + current); 37 | return super.getRemoteModel(name, sleep); 38 | } 39 | 40 | @AsyncMethodDef(timeout = 10, inheritThreadLocal = true, 41 | methodThreadPoolConf = @AsyncThreadPoolConfig(effect = true)) 42 | public AsyncLoadTestModel getRemoteModel1(String name, long sleep) { 43 | System.out.println( 44 | "-----getRemoteModel_1-----threadLocal----" + AsyncThreadLocalInheriteTest.get()); 45 | 46 | Thread current = Thread.currentThread(); 47 | System.out.println("线程信息:" + current); 48 | return super.getRemoteModel(name, sleep); 49 | } 50 | 51 | @Override 52 | public List listRemoteModel(String name, long sleep) { 53 | return super.listRemoteModel(name, sleep); 54 | } 55 | 56 | @Override 57 | @AsyncMethodDef 58 | public Integer countRemoteModel(String name, long sleep) { 59 | return super.countRemoteModel(name, sleep); 60 | } 61 | 62 | @Override 63 | public void updateRemoteModel(String name, long sleep) { 64 | super.updateRemoteModel(name, sleep); 65 | } 66 | 67 | @Override 68 | public String getRemoteName(String name, long sleep) { 69 | return super.getRemoteName(name, sleep); 70 | } 71 | 72 | @Override 73 | public Object getRemoteObject(String name, long sleep) { 74 | return super.getRemoteObject(name, sleep); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /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(getDefaultTimeout()); 29 | config.setNeedBarrierSupport(getNeedBarrierSupport()); 30 | config.setNeedThreadLocalSupport(getNeedThreadLocalSupport()); 31 | config.setMatches(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 | /* (non-Javadoc) 75 | * @see java.lang.Object#toString() 76 | */ 77 | @Override 78 | public String toString() { 79 | return "AsyncLoadConfig [defaultTimeout=" + defaultTimeout + ", needBarrierSupport=" 80 | + needBarrierSupport + ", needThreadLocalSupport=" + needThreadLocalSupport 81 | + ", matches=" + matches + "]"; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /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/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/main/java/com/alibaba/asyncload/impl/annotation/AsyncLoadHandlerAdvice.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadHandlerAop.java 3 | * author: yujiakui 4 | * 2018年4月17日 5 | * 下午6:44:08 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import java.lang.reflect.Method; 10 | import java.text.MessageFormat; 11 | import java.util.Map; 12 | 13 | import org.aspectj.lang.ProceedingJoinPoint; 14 | import org.aspectj.lang.Signature; 15 | import org.aspectj.lang.annotation.Around; 16 | import org.aspectj.lang.annotation.Aspect; 17 | import org.aspectj.lang.annotation.Pointcut; 18 | import org.aspectj.lang.reflect.MethodSignature; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.context.annotation.EnableAspectJAutoProxy; 23 | import org.springframework.stereotype.Component; 24 | import org.springframework.util.CollectionUtils; 25 | 26 | import com.alibaba.asyncload.impl.AsyncLoadPerl5RegexpMethodMatcher; 27 | import com.alibaba.asyncload.impl.util.MethodFilterUtil; 28 | 29 | /** 30 | * @author yujiakui 31 | * 32 | * 下午6:44:08 33 | * 34 | * 异步加载处理aop 35 | * 36 | */ 37 | // 使用cglib代理生成目标类 38 | @EnableAspectJAutoProxy(proxyTargetClass = true) 39 | @Component 40 | @Aspect 41 | public class AsyncLoadHandlerAdvice { 42 | 43 | /** logger */ 44 | private static final Logger LOGGER = LoggerFactory.getLogger(AsyncLoadHandlerAdvice.class); 45 | 46 | /** 异步加载处理工厂类 */ 47 | @Autowired 48 | private AsyncLoadHandleFactory asyncLoadHandleFactory; 49 | 50 | @Pointcut("@within(com.alibaba.asyncload.impl.annotation.AsyncClassDef)") 51 | public void aspectjMethod() { 52 | } 53 | 54 | /** 55 | * Around 手动控制调用核心业务逻辑,以及调用前和调用后的处理, 56 | * 57 | * @param pjp 58 | * @return 59 | * @throws Throwable 60 | */ 61 | @Around(value = "aspectjMethod()") 62 | public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { 63 | // 对方法进行过滤 64 | if (MethodFilterUtil.filterMethod(pjp) || !isNeedAsyncLoad(pjp)) { 65 | return pjp.proceed(); 66 | } else { 67 | LOGGER.info(MessageFormat.format("异步并行框架处理开始pjp={0}", pjp.toShortString())); 68 | return asyncLoadHandleFactory.handle(pjp); 69 | } 70 | } 71 | 72 | /** 73 | * 是否需要异步处理 74 | * 75 | * @param pjp 76 | * @return 77 | */ 78 | private boolean isNeedAsyncLoad(ProceedingJoinPoint pjp) { 79 | 80 | Map classMethodMatchMap = AsyncLoadAnnotationThreadLocal 81 | .getAsyncLoadMap(); 82 | if (!CollectionUtils.isEmpty(classMethodMatchMap)) { 83 | Class originClassObj = pjp.getTarget().getClass(); 84 | String[] methodRegexMatchs = classMethodMatchMap.get(originClassObj.getName()); 85 | // 获取通用类 86 | if (null == methodRegexMatchs) { 87 | methodRegexMatchs = classMethodMatchMap 88 | .get(AsyncLoadAnnotationConstants.ALL_CLASSES); 89 | } 90 | if (null != methodRegexMatchs && methodRegexMatchs.length != 0) { 91 | // 根据签名获得方法参数 92 | Signature signature = pjp.getSignature(); 93 | MethodSignature methodSignature = (MethodSignature) signature; 94 | Method method = methodSignature.getMethod(); 95 | 96 | AsyncLoadPerl5RegexpMethodMatcher regexMethodMatcher = new AsyncLoadPerl5RegexpMethodMatcher(); 97 | regexMethodMatcher.setPatterns(methodRegexMatchs); 98 | return regexMethodMatcher.matches(method); 99 | } 100 | 101 | } 102 | return false; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /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/main/java/com/alibaba/asyncload/impl/annotation/AsyncLoadEnableAdvice.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadEnableAdvice.java 3 | * author: yujiakui 4 | * 2018年4月19日 5 | * 下午1:52:23 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import java.lang.reflect.Method; 10 | import java.text.MessageFormat; 11 | import java.util.Map; 12 | 13 | import org.aspectj.lang.ProceedingJoinPoint; 14 | import org.aspectj.lang.Signature; 15 | import org.aspectj.lang.annotation.Around; 16 | import org.aspectj.lang.annotation.Aspect; 17 | import org.aspectj.lang.annotation.Pointcut; 18 | import org.aspectj.lang.reflect.MethodSignature; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.springframework.stereotype.Component; 22 | 23 | import com.alibaba.asyncload.impl.util.MethodFilterUtil; 24 | import com.google.common.collect.Maps; 25 | 26 | /** 27 | * @author yujiakui 28 | * 29 | * 下午1:52:23 30 | * 31 | * 异步加载开启切面 32 | */ 33 | @Component 34 | @Aspect 35 | public class AsyncLoadEnableAdvice { 36 | 37 | /** logger */ 38 | private static final Logger LOGGER = LoggerFactory.getLogger(AsyncLoadEnableAdvice.class); 39 | 40 | @Pointcut("@within(com.alibaba.asyncload.impl.annotation.EnableAsyncClass)") 41 | public void aspectjMethod() { 42 | } 43 | 44 | /** 45 | * Around 手动控制调用核心业务逻辑,以及调用前和调用后的处理, 46 | * 47 | * @param pjp 48 | * @return 49 | * @throws Throwable 50 | */ 51 | @Around(value = "aspectjMethod()") 52 | public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { 53 | 54 | boolean isAsyncFlag = false; 55 | 56 | // 对方法进行过滤 57 | if (!MethodFilterUtil.filterMethod(pjp)) { 58 | LOGGER.info(MessageFormat.format("异步并行框架Enable处理开始pjp={0}", pjp.toShortString())); 59 | // 根据签名获得方法参数 60 | EnableAsyncClassMethodInfo[] enableAsyncClassMethodInfos = getEnableInfoFromMethod(pjp); 61 | if (null != enableAsyncClassMethodInfos && enableAsyncClassMethodInfos.length != 0) { 62 | Map asynClassMethodInfoMap = Maps.newHashMap(); 63 | for (EnableAsyncClassMethodInfo enableAsyncClassMethodInfo2 : enableAsyncClassMethodInfos) { 64 | asynClassMethodInfoMap.put(enableAsyncClassMethodInfo2.classFullName(), 65 | enableAsyncClassMethodInfo2.methodMatchRegex()); 66 | } 67 | // 向threadLocal中放入对应的值 68 | AsyncLoadAnnotationThreadLocal.setAsyncLoadMap(asynClassMethodInfoMap); 69 | isAsyncFlag = true; 70 | } 71 | } 72 | Object result = null; 73 | try { 74 | result = pjp.proceed(); 75 | } finally { 76 | if (isAsyncFlag) { 77 | // 清除threadLocal中放入的信息 78 | AsyncLoadAnnotationThreadLocal.removeAsyncLoadMap(); 79 | } 80 | } 81 | 82 | return result; 83 | } 84 | 85 | /** 86 | * 获取方法上的对应的enable信息,从方法上和类上合并,如果方法上没有则去类上的 87 | * 88 | * @param pjp 89 | * @return 90 | */ 91 | private EnableAsyncClassMethodInfo[] getEnableInfoFromMethod(ProceedingJoinPoint pjp) { 92 | 93 | Signature signature = pjp.getSignature(); 94 | MethodSignature methodSignature = (MethodSignature) signature; 95 | Method method = methodSignature.getMethod(); 96 | EnableAsyncMethod enableAsyncMethod = method.getAnnotation(EnableAsyncMethod.class); 97 | if (null == enableAsyncMethod) { 98 | // 从类上面的注解取 99 | Class originClassObj = pjp.getTarget().getClass(); 100 | EnableAsyncClass enableAsyncClass = originClassObj 101 | .getAnnotation(EnableAsyncClass.class); 102 | return enableAsyncClass.classMethodInfos(); 103 | } 104 | return enableAsyncMethod.classMethodInfos(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /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/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.enums.PoolRejectHandleMode; 10 | import com.alibaba.asyncload.impl.pool.AsyncLoadCallable; 11 | import com.alibaba.asyncload.impl.pool.AsyncLoadFuture; 12 | import com.alibaba.asyncload.impl.pool.AsyncLoadThreadPool; 13 | import com.alibaba.asyncload.impl.pool.NamedThreadFactory; 14 | 15 | /** 16 | * 异步加载的具体执行任务者, 支持Runable和Callable两种 17 | * 18 | * @author jianghang 2011-1-21 下午11:32:31 19 | */ 20 | public class AsyncLoadExecutor { 21 | 22 | public static final int DEFAULT_POOL_SIZE = 20; 23 | public static final int DEFAULT_ACCEPT_COUNT = 100; 24 | public static final PoolRejectHandleMode DEFAULT_MODE = PoolRejectHandleMode.REJECT; 25 | private int poolSize; 26 | private int acceptCount; // 等待队列长度,避免无限制提交请求 27 | private PoolRejectHandleMode mode; // 默认为拒绝服务,用于控制accept队列满了以后的处理方式 28 | private AsyncLoadThreadPool pool; 29 | private volatile boolean isInit = false; 30 | 31 | public AsyncLoadExecutor() { 32 | this(DEFAULT_POOL_SIZE, DEFAULT_ACCEPT_COUNT, DEFAULT_MODE); 33 | } 34 | 35 | public AsyncLoadExecutor(int poolSize) { 36 | this(poolSize, DEFAULT_ACCEPT_COUNT, DEFAULT_MODE); 37 | } 38 | 39 | public AsyncLoadExecutor(int poolSize, int acceptCount) { 40 | this(poolSize, acceptCount, DEFAULT_MODE); 41 | } 42 | 43 | public AsyncLoadExecutor(int poolSize, int acceptCount, PoolRejectHandleMode mode) { 44 | this.poolSize = poolSize; 45 | this.acceptCount = acceptCount; 46 | this.mode = mode; 47 | } 48 | 49 | public void initital() { 50 | if (isInit == false) { 51 | RejectedExecutionHandler handler = getHandler(mode); 52 | BlockingQueue queue = getBlockingQueue(acceptCount, mode); 53 | // 构造pool池 54 | pool = new AsyncLoadThreadPool(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue, 55 | new NamedThreadFactory(), handler); 56 | 57 | isInit = true; 58 | } 59 | } 60 | 61 | public void destory() { 62 | if (isInit && pool != null) { 63 | pool.shutdown(); 64 | pool = null; 65 | 66 | isInit = false; 67 | } 68 | } 69 | 70 | public AsyncLoadFuture submit(AsyncLoadCallable task) { 71 | return pool.submit(task); 72 | } 73 | 74 | // ==================== help method =========================== 75 | 76 | private BlockingQueue getBlockingQueue(int acceptCount, PoolRejectHandleMode mode) { 77 | if (acceptCount < 0) { 78 | return new LinkedBlockingQueue(); 79 | } else if (acceptCount == 0) { 80 | return new ArrayBlockingQueue(1); // 等于0时等价于队列1 81 | } else { 82 | return new ArrayBlockingQueue(acceptCount); 83 | } 84 | } 85 | 86 | private RejectedExecutionHandler getHandler(PoolRejectHandleMode mode) { 87 | return PoolRejectHandleMode.REJECT == mode ? new AsyncLoadThreadPool.AbortPolicy() 88 | : new AsyncLoadThreadPool.CallerRunsPolicy(); 89 | } 90 | 91 | // ====================== setter / getter ========================== 92 | 93 | public void setPoolSize(int poolSize) { 94 | this.poolSize = poolSize; 95 | } 96 | 97 | public void setAcceptCount(int acceptCount) { 98 | this.acceptCount = acceptCount; 99 | } 100 | 101 | public void setMode(PoolRejectHandleMode mode) { 102 | this.mode = mode; 103 | } 104 | 105 | public void setMode(String mode) { 106 | this.mode = PoolRejectHandleMode.valueOf(mode); 107 | } 108 | 109 | // ======================= help method ========================== 110 | 111 | @Override 112 | public String toString() { 113 | return "AsyncLoadExecutor [ poolSize=" + poolSize + ", acceptCount=" + acceptCount 114 | + ", mode=" + mode + "]"; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /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/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/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/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/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 | -------------------------------------------------------------------------------- /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/main/java/com/alibaba/asyncload/impl/annotation/AsyncLoadHandleFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncLoadHandleFactory.java 3 | * author: yujiakui 4 | * 2018年4月17日 5 | * 下午6:48:35 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import java.lang.reflect.Method; 10 | import java.text.MessageFormat; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import org.aspectj.lang.ProceedingJoinPoint; 15 | import org.aspectj.lang.Signature; 16 | import org.aspectj.lang.reflect.MethodSignature; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.stereotype.Component; 21 | import org.springframework.util.CollectionUtils; 22 | 23 | import com.alibaba.asyncload.AsyncLoadMethodMatch; 24 | import com.alibaba.asyncload.impl.template.AsyncLoadTemplate; 25 | import com.google.common.collect.Maps; 26 | 27 | /** 28 | * @author yujiakui 29 | * 30 | * 下午6:48:35 31 | * 32 | * 异步处理加载工厂 33 | */ 34 | @Component 35 | public class AsyncLoadHandleFactory { 36 | 37 | /** 日志 */ 38 | private final static Logger LOGGER = LoggerFactory.getLogger(AsyncLoadHandleFactory.class); 39 | 40 | /** 异步注解解析工厂 */ 41 | @Autowired 42 | private AsyncAnnotationParserFactory asyncAnnotationParserFactory; 43 | 44 | /** 45 | * 拦截方法对应的处理 46 | * 47 | * @param pjp 48 | * @return 49 | * @throws Throwable 50 | */ 51 | public Object handle(ProceedingJoinPoint pjp) throws Throwable { 52 | // 根据签名获得方法参数 53 | Signature signature = pjp.getSignature(); 54 | MethodSignature methodSignature = (MethodSignature) signature; 55 | Method method = methodSignature.getMethod(); 56 | 57 | // Class originClassObj = 58 | // AopProxyUtils.ultimateTargetClass(pjp.getThis()); 59 | Class originClassObj = pjp.getTarget().getClass(); 60 | 61 | // 获得对应的拦截类名 62 | String classFullName = originClassObj.getName(); 63 | 64 | // 1. 先从模板中获取 65 | HandleResult handleResult = handleMethodTemplate(pjp, method, classFullName); 66 | if (handleResult.isSuccess()) { 67 | return handleResult.getResult(); 68 | } 69 | 70 | // 2. 在从方法正则表达式中进行匹配 71 | handleResult = methodMatchAsyncHandle(pjp, method, classFullName); 72 | if (handleResult.isSuccess()) { 73 | return handleResult.getResult(); 74 | } 75 | 76 | return pjp.proceed(); 77 | 78 | } 79 | 80 | /** 81 | * @param pjp 82 | * @param method 83 | * @param classFullName 84 | */ 85 | private HandleResult methodMatchAsyncHandle(ProceedingJoinPoint pjp, Method method, 86 | String classFullName) { 87 | List asyncLoadTemplates = asyncAnnotationParserFactory 88 | .getMethodConfExecMap().get(classFullName); 89 | if (!CollectionUtils.isEmpty(asyncLoadTemplates)) { 90 | for (AsyncLoadTemplate asyncLoadTemplate : asyncLoadTemplates) { 91 | // 获得对应的matcher 92 | Map matchMap = asyncLoadTemplate.getConfig() 93 | .getMatches(); 94 | // 对应的配置中只能有一个match,所以仅仅去一个 95 | for (Map.Entry entry : matchMap.entrySet()) { 96 | AsyncLoadMethodMatch match = entry.getKey(); 97 | // 方法匹配标记 98 | boolean matchFlag = match.matches(method); 99 | if (matchFlag) { 100 | updateMethodAsyncTemplate(method, classFullName, asyncLoadTemplate); 101 | return new HandleResult(asyncLoadTemplate.execute(pjp), true); 102 | } 103 | } 104 | } 105 | } 106 | return new HandleResult(null, false); 107 | } 108 | 109 | /** 110 | * @param method 111 | * @param classFullName 112 | * @param asyncLoadTemplate 113 | */ 114 | private void updateMethodAsyncTemplate(Method method, String classFullName, 115 | AsyncLoadTemplate asyncLoadTemplate) { 116 | Map> methodAsyncTemplateTable = asyncAnnotationParserFactory 117 | .getMethodAsyncTemplateTable(); 118 | Map methodAsyncTemplateMap = methodAsyncTemplateTable 119 | .get(classFullName); 120 | if (CollectionUtils.isEmpty(methodAsyncTemplateMap)) { 121 | methodAsyncTemplateMap = Maps.newConcurrentMap(); 122 | methodAsyncTemplateTable.put(classFullName, methodAsyncTemplateMap); 123 | } 124 | methodAsyncTemplateMap.put(method, asyncLoadTemplate); 125 | 126 | LOGGER.info( 127 | MessageFormat.format("异步并行加载在table中增加对应的方法table={0}", methodAsyncTemplateTable)); 128 | } 129 | 130 | /** 131 | * @param pjp 132 | * @param method 133 | * @param classFullName 134 | */ 135 | private HandleResult handleMethodTemplate(ProceedingJoinPoint pjp, Method method, 136 | String classFullName) { 137 | Map> methodAsyncTemplateTable = asyncAnnotationParserFactory 138 | .getMethodAsyncTemplateTable(); 139 | Map methodTemplateMap = methodAsyncTemplateTable 140 | .get(classFullName); 141 | if (!CollectionUtils.isEmpty(methodTemplateMap)) { 142 | AsyncLoadTemplate asyncLoadTemplate = methodTemplateMap.get(method); 143 | if (null != asyncLoadTemplate) { 144 | LOGGER.info( 145 | MessageFormat.format("执行异步并行方法{0}对应template={1}", pjp, asyncLoadTemplate)); 146 | return new HandleResult(asyncLoadTemplate.execute(pjp), true); 147 | } 148 | } 149 | return new HandleResult(null, false); 150 | } 151 | 152 | class HandleResult { 153 | private boolean success; 154 | private Object result; 155 | 156 | public HandleResult(Object result, boolean success) { 157 | this.result = result; 158 | this.success = success; 159 | } 160 | 161 | /** 162 | * @return the success 163 | */ 164 | public boolean isSuccess() { 165 | return success; 166 | } 167 | 168 | /** 169 | * @param success 170 | * the success to set 171 | */ 172 | public void setSuccess(boolean success) { 173 | this.success = success; 174 | } 175 | 176 | /** 177 | * @return the result 178 | */ 179 | public Object getResult() { 180 | return result; 181 | } 182 | 183 | /** 184 | * @param result 185 | * the result to set 186 | */ 187 | public void setResult(Object result) { 188 | this.result = result; 189 | } 190 | 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.alibaba.asyncload 6 | asyncload 7 | 1.0.1-SNAPSHOT 8 | jar 9 | asyncload 10 | https://github.com/alibaba/asyncload 11 | 12 | 13 | org.sonatype.oss 14 | oss-parent 15 | 7 16 | 17 | 18 | 19 | agapple 20 | http://agapple.iteye.com 21 | jianghang115@gmail.com 22 | 8 23 | 24 | 25 | 26 | 27 | Apache License, Version 2.0 28 | http://www.apache.org/licenses/LICENSE-2.0 29 | 30 | 31 | 32 | 33 | git@github.com:alibaba/asyncload.git 34 | scm:git:git@github.com:alibaba/asyncload.git 35 | scm:git:git@github.com:alibaba/asyncload.git 36 | 37 | 38 | 39 | UTF-8 40 | 41 | false 42 | true 43 | 44 | 1.8 45 | 1.8 46 | UTF-8 47 | 48 | 49 | 50 | 51 | org.springframework 52 | spring-test 53 | 4.3.10.RELEASE 54 | compile 55 | 56 | 57 | 58 | org.springframework 59 | spring-context 60 | 4.3.9.RELEASE 61 | compile 62 | 63 | 64 | 65 | org.springframework 66 | spring-aop 67 | 4.3.11.RELEASE 68 | 69 | 70 | 71 | org.aspectj 72 | aspectjweaver 73 | 1.8.10 74 | 75 | 76 | 77 | org.aspectj 78 | aspectjrt 79 | 1.8.10 80 | 81 | 82 | 83 | cglib 84 | cglib 85 | 3.1 86 | 87 | 88 | asm 89 | asm 90 | 3.1 91 | 92 | 93 | 94 | oro 95 | oro 96 | 2.0.8 97 | 98 | 99 | 100 | junit 101 | junit 102 | 4.12 103 | test 104 | 105 | 106 | 107 | 108 | org.slf4j 109 | slf4j-api 110 | 1.7.25 111 | compile 112 | 113 | 114 | 115 | org.slf4j 116 | slf4j-simple 117 | 1.7.25 118 | test 119 | 120 | 121 | javassist 122 | javassist 123 | 3.11.0.GA 124 | test 125 | 126 | 127 | 128 | com.google.guava 129 | guava 130 | 23.0 131 | 132 | 133 | 134 | 135 | 136 | 137 | org.jvnet.wagon-svn 138 | wagon-svn 139 | 1.9 140 | 141 | 142 | org.apache.maven.wagon 143 | wagon-http-shared 144 | 1.0-beta-7 145 | 146 | 147 | 148 | 149 | org.apache.maven.plugins 150 | maven-compiler-plugin 151 | 152 | ${java_source_version} 153 | ${java_target_version} 154 | ${file_encoding} 155 | 156 | 157 | 158 | org.apache.maven.plugins 159 | maven-eclipse-plugin 160 | 2.5.1 161 | 162 | 163 | 164 | .settings/org.eclipse.core.resources.prefs 165 | 166 | =${file_encoding}${line.separator}]]> 167 | 168 | 169 | 170 | 171 | 172 | 173 | org.apache.maven.plugins 174 | maven-surefire-plugin 175 | 2.5 176 | 177 | 178 | **/*Test.java 179 | 180 | 181 | **/*NoRunTest.java 182 | 183 | 184 | 185 | 186 | src/main/java 187 | src/test/java 188 | 189 | 190 | src/main/resources 191 | 192 | **/* 193 | 194 | 195 | **/.svn/ 196 | 197 | 198 | 199 | 200 | 201 | src/test/resources 202 | 203 | **/* 204 | 205 | 206 | **/.svn/ 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | sonatype-nexus-snapshots 215 | Sonatype Nexus Snapshots 216 | https://oss.sonatype.org/content/repositories/snapshots/ 217 | 218 | 219 | sonatype-nexus-staging 220 | Nexus Release Repository 221 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /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/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/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.util.ClassUtils; 24 | import org.springframework.util.PatternMatchUtils; 25 | import org.springframework.util.ReflectionUtils; 26 | import org.springframework.util.StringUtils; 27 | 28 | /** 29 | * 提供一种机制:无侵入的拦截机制,与现有的bean定义进行融合。实现自定义的{@linkplain BeanPostProcessor}进行替换,部分代码copy 30 | * from {@linkplain AbstractAutoProxyCreator} 31 | * 32 | *
 33 |  * 融合的规则:
 34 |  * 1. 原先的bean是{@linkplain ProxyFactoryBean},则将自己的拦截器定义和proxy bean的定义进行融合,只是会合并原先的拦截器定义,其他的不做融合
 35 |  *    可通过applyCommonInterceptorsFirst=true/false指定顺序.如果是false则{@linkplain CompositeAutoProxyCreator}定义的拦截器排在后面
 36 |  * 2. 如果原先的bean是除{@linkplain ProxyFactoryBean}的bean,则尝试自动创建ProxyFactoryBean,对应的拦截器也仅是所配置的拦截器列表,不会进行自动的扫描和装配
 37 |  * 3. 其他的类似:{@linkplain TransactionProxyFactoryBean}并不会进行一个融合的处理
 38 |  *
 39 |  * 
40 | * 41 | * @author jianghang 2011-4-25 上午10:43:12 42 | */ 43 | public class CompositeAutoProxyCreator extends ProxyConfig implements BeanPostProcessor, Ordered, 44 | BeanClassLoaderAware, BeanFactoryAware, AopInfrastructureBean { 45 | 46 | private static final long serialVersionUID = 8458055362270662345L; 47 | private static final Field interceptorNamesField = ReflectionUtils 48 | .findField(ProxyFactoryBean.class, "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 | @Override 60 | public Object postProcessBeforeInitialization(Object bean, String beanName) { 61 | // 不做处理 62 | return bean; 63 | } 64 | 65 | @Override 66 | public Object postProcessAfterInitialization(Object bean, String beanName) 67 | throws BeansException { 68 | if (bean != null) { 69 | Object cacheKey = getCacheKey(bean.getClass(), beanName); 70 | return wrapIfNecessary(bean, beanName, cacheKey); 71 | } 72 | 73 | return bean; 74 | } 75 | 76 | protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { 77 | if (nonAdvisedBeans.contains(cacheKey)) { 78 | return bean; 79 | } 80 | if (isInfrastructureClass(bean.getClass())) { 81 | nonAdvisedBeans.add(cacheKey); 82 | return bean; 83 | } 84 | // 不能进行代理cache,singleton的实现有spring core核心机制来保证,如果是singleton不会回调多次 85 | // Create proxy if we have advice. 86 | if (beanNames != null) { 87 | for (Iterator it = beanNames.iterator(); it.hasNext();) { 88 | String mappedName = (String) it.next(); 89 | if (isMatch(beanName, mappedName)) { 90 | if (ProxyFactoryBean.class.isAssignableFrom(bean.getClass())) { 91 | ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean; 92 | String[] orignInterceptorNames = getInterceptorFromProxyFactoryBean( 93 | proxyFactoryBean); 94 | String[] newInterceptorNames = new String[orignInterceptorNames.length 95 | + interceptorNames.length]; 96 | if (applyCommonInterceptorsFirst) {// 如果是true,则将Auto-proxy的拦截器定义到最前面 97 | // 构造新的的拦截器列表 98 | System.arraycopy(interceptorNames, 0, newInterceptorNames, 0, 99 | interceptorNames.length); 100 | System.arraycopy(orignInterceptorNames, 0, newInterceptorNames, 101 | interceptorNames.length, orignInterceptorNames.length); 102 | } else { 103 | System.arraycopy(orignInterceptorNames, 0, newInterceptorNames, 0, 104 | orignInterceptorNames.length); 105 | System.arraycopy(interceptorNames, 0, newInterceptorNames, 106 | orignInterceptorNames.length, interceptorNames.length); 107 | } 108 | // 重新设置新的inteceptorNames 109 | proxyFactoryBean.setInterceptorNames(newInterceptorNames); 110 | return proxyFactoryBean; 111 | } else { 112 | // 如果是单例,对应的代理bean对象为同一个 113 | ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); 114 | proxyFactoryBean.setBeanFactory(beanFactory); 115 | proxyFactoryBean.setBeanClassLoader(proxyClassLoader); 116 | proxyFactoryBean.setInterceptorNames(interceptorNames); 117 | proxyFactoryBean.copyFrom(this); // 拷贝对应的一些Proxy config 118 | proxyFactoryBean.setTarget(bean); 119 | return proxyFactoryBean.getObject(); 120 | } 121 | } 122 | } 123 | } 124 | 125 | nonAdvisedBeans.add(cacheKey); 126 | return bean; 127 | } 128 | 129 | // =========================== helper method 130 | // ================================ 131 | 132 | private String[] getInterceptorFromProxyFactoryBean(ProxyFactoryBean bean) { 133 | synchronized (interceptorNamesField) { 134 | try { 135 | interceptorNamesField.setAccessible(true); 136 | try { 137 | Object obj = interceptorNamesField.get(bean); 138 | return obj != null ? (String[]) obj : new String[0]; 139 | } catch (Exception e) { 140 | throw new RuntimeException(e); 141 | } 142 | } finally { 143 | interceptorNamesField.setAccessible(false); 144 | } 145 | } 146 | 147 | } 148 | 149 | /** 150 | * 对应的内存cache的key 151 | */ 152 | protected Object getCacheKey(Class beanClass, String beanName) { 153 | return beanClass.getName() + "_" + beanName; 154 | } 155 | 156 | /** 157 | * 不对基础的框架类做auto-proxy 158 | * 159 | * @param beanClass 160 | * @return 161 | */ 162 | protected boolean isInfrastructureClass(Class beanClass) { 163 | return Advisor.class.isAssignableFrom(beanClass) || Advice.class.isAssignableFrom(beanClass) 164 | || AopInfrastructureBean.class.isAssignableFrom(beanClass); 165 | } 166 | 167 | /** 168 | * 返回是否匹配,支持简单的通配符: "xxx*", "*xxx" "*xxx*" 169 | */ 170 | protected boolean isMatch(String beanName, String mappedName) { 171 | return PatternMatchUtils.simpleMatch(mappedName, beanName); 172 | } 173 | 174 | // ========================= setter / getter =========================== 175 | 176 | public final void setOrder(int order) { 177 | this.order = order; 178 | } 179 | 180 | @Override 181 | public final int getOrder() { 182 | return order; 183 | } 184 | 185 | public void setInterceptorNames(String[] interceptorNames) { 186 | this.interceptorNames = interceptorNames; 187 | } 188 | 189 | public void setApplyCommonInterceptorsFirst(boolean applyCommonInterceptorsFirst) { 190 | this.applyCommonInterceptorsFirst = applyCommonInterceptorsFirst; 191 | } 192 | 193 | @Override 194 | public void setBeanClassLoader(ClassLoader classLoader) { 195 | if (!classLoaderConfigured) { 196 | proxyClassLoader = classLoader; 197 | } 198 | } 199 | 200 | @Override 201 | public void setBeanFactory(BeanFactory beanFactory) { 202 | this.beanFactory = beanFactory; 203 | } 204 | 205 | public void setBeanNames(String[] beanNames) { 206 | this.beanNames = new ArrayList(beanNames.length); 207 | for (int i = 0; i < beanNames.length; i++) { 208 | this.beanNames.add(StringUtils.trimWhitespace(beanNames[i])); 209 | } 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /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 org.aspectj.lang.ProceedingJoinPoint; 10 | import org.aspectj.lang.Signature; 11 | import org.aspectj.lang.reflect.MethodSignature; 12 | 13 | import com.alibaba.asyncload.AsyncLoadConfig; 14 | import com.alibaba.asyncload.AsyncLoadExecutor; 15 | import com.alibaba.asyncload.impl.AsyncLoadObject; 16 | import com.alibaba.asyncload.impl.AsyncLoadResult; 17 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 18 | import com.alibaba.asyncload.impl.pool.AsyncLoadCallable; 19 | import com.alibaba.asyncload.impl.util.AsyncLoadBarrier; 20 | import com.alibaba.asyncload.impl.util.AsyncLoadUtils; 21 | 22 | /** 23 | * 基于template模式提供的一套AsyncLoad机制,编程式 24 | * 25 | * @author jianghang 2011-1-24 下午07:01:07 26 | */ 27 | public class AsyncLoadTemplate { 28 | 29 | private AsyncLoadExecutor executor; 30 | private AsyncLoadConfig config = new AsyncLoadConfig(); 31 | 32 | /** 33 | * 异步执行callback模板,设置默认的超时时间,同时返回对应的proxy model,执行AsyncLoad 34 | * 35 | * @param 36 | * @param callback 37 | * @return 38 | */ 39 | public R execute(AsyncLoadCallback callback) { 40 | return execute(callback, config); 41 | } 42 | 43 | /** 44 | * 异步执行callback模板,设置默认的超时时间,同时返回对应的proxy model,执行AsyncLoad 45 | * 46 | * @param 47 | * @param callback 48 | * @return 49 | */ 50 | public Object execute(final ProceedingJoinPoint proceedingJoinPoint) { 51 | 52 | AsyncLoadCallback asyncLoadCallback = new AsyncLoadCallback() { 53 | @Override 54 | public Object doAsyncLoad() { 55 | try { 56 | return proceedingJoinPoint.proceed(); 57 | } catch (Throwable throwable) { 58 | throw new AsyncLoadException(throwable); 59 | } 60 | } 61 | }; 62 | 63 | Signature signature = proceedingJoinPoint.getSignature(); 64 | MethodSignature methodSignature = (MethodSignature) signature; 65 | Class returnClass = methodSignature.getReturnType(); 66 | 67 | // 初始化执行器 68 | executor.initital(); 69 | 70 | return execute(asyncLoadCallback, returnClass, config); 71 | } 72 | 73 | /** 74 | * 异步执行callback模板,同时返回对应的proxy model,执行AsyncLoad 75 | * 76 | * @param 77 | * @param callback 78 | * @param timeout 79 | * @return 80 | */ 81 | public R execute(final AsyncLoadCallback callback, long timeout) { 82 | AsyncLoadUtils.notNull(callback, "callback is null!"); 83 | 84 | Type type = callback.getClass().getGenericInterfaces()[0]; 85 | if (!(type instanceof ParameterizedType)) { 86 | // 用户不指定AsyncLoadCallBack的泛型信息 87 | throw new AsyncLoadException( 88 | "you should specify AsyncLoadCallBack for R type, ie: AsyncLoadCallBack"); 89 | } 90 | Class returnClass = getGenericClass((ParameterizedType) type, 0); 91 | 92 | AsyncLoadConfig copy = config.cloneConfig(); 93 | copy.setDefaultTimeout(timeout); 94 | return execute(callback, returnClass, copy); 95 | } 96 | 97 | /** 98 | * 异步执行callback模板,设置默认的超时时间,同时返回对应的proxy model,执行AsyncLoad 99 | * 100 | * @param 101 | * @param callback 102 | * @param returnClass 103 | * 期望的返回对象class 104 | * @return 105 | */ 106 | public R execute(AsyncLoadCallback callback, Class returnClass) { 107 | return execute(callback, returnClass, config); 108 | } 109 | 110 | /** 111 | * 异步执行callback模板,同时返回对应的proxy model,执行AsyncLoad 112 | * 113 | * @param 114 | * @param callback 115 | * @param returnClass 116 | * 期望的返回对象class 117 | * @param timeout 118 | * @return 119 | */ 120 | public R execute(final AsyncLoadCallback callback, Class returnClass, long timeout) { 121 | AsyncLoadConfig copy = config.cloneConfig(); 122 | copy.setDefaultTimeout(timeout); 123 | return execute(callback, returnClass, copy); 124 | } 125 | 126 | /** 127 | * 异步执行callback模板,传递config对象 128 | * 129 | * @param 130 | * @param callback 131 | * @param config 132 | * @return 133 | */ 134 | public R execute(final AsyncLoadCallback callback, AsyncLoadConfig config) { 135 | AsyncLoadUtils.notNull(callback, "callback is null!"); 136 | 137 | Type type = callback.getClass().getGenericInterfaces()[0]; 138 | if (!(type instanceof ParameterizedType)) { 139 | // 用户不指定AsyncLoadCallBack的泛型信息 140 | throw new AsyncLoadException( 141 | "you should specify AsyncLoadCallBack for R type, ie: AsyncLoadCallBack"); 142 | } 143 | Class returnClass = getGenericClass((ParameterizedType) type, 0); 144 | return execute(callback, returnClass, config); 145 | } 146 | 147 | /** 148 | * 异步执行callback模板,传递config对象 149 | * 150 | * @param 151 | * @param callback 152 | * @param returnClass 153 | * @param config 154 | * @return 155 | */ 156 | public R execute(final AsyncLoadCallback callback, Class returnClass, 157 | AsyncLoadConfig config) { 158 | AsyncLoadUtils.notNull(callback, "callback is null!"); 159 | AsyncLoadUtils.notNull(returnClass, "returnClass is null!"); 160 | AsyncLoadUtils.notNull(config, "config is null!"); 161 | 162 | if (Void.TYPE.isAssignableFrom(returnClass)) {// 判断返回值是否为void 163 | // 不处理void的函数调用 164 | return callback.doAsyncLoad(); 165 | } else if (!Modifier.isPublic(returnClass.getModifiers())) { 166 | // 处理如果是非public属性,则不进行代理,强制访问会出现IllegalAccessException,比如一些内部类或者匿名类不允许直接访问 167 | return callback.doAsyncLoad(); 168 | } else if (Modifier.isFinal(returnClass.getModifiers())) { 169 | // 处理特殊的final类型,目前暂不支持,后续可采用jdk proxy 170 | return callback.doAsyncLoad(); 171 | } else if (returnClass.isPrimitive() || returnClass.isArray()) { 172 | // 不处理特殊类型,因为无法使用cglib代理 173 | return callback.doAsyncLoad(); 174 | } else if (returnClass == Object.class) { 175 | // 针对返回对象是Object类型,不做代理。没有具体的method,代理没任何意义 176 | return callback.doAsyncLoad(); 177 | } else { 178 | final AsyncLoadConfig copy = config; 179 | System.out 180 | .println("------executor addr=" + executor.hashCode() + ";content=" + executor); 181 | Future future = executor.submit(new AsyncLoadCallable() { 182 | 183 | @Override 184 | public R call() throws Exception { 185 | System.out.println("------doAsyncLoad-----"); 186 | return callback.doAsyncLoad(); 187 | } 188 | 189 | @Override 190 | public AsyncLoadConfig getConfig() { 191 | return copy; 192 | } 193 | }); 194 | // 够造一个返回的AsyncLoadResult 195 | AsyncLoadResult result = new AsyncLoadResult(returnClass, future, 196 | config.getDefaultTimeout()); 197 | // 继续返回一个代理对象 198 | R asyncProxy = (R) result.getProxy(); 199 | // 添加到barrier中 200 | if (config.getNeedBarrierSupport()) { 201 | AsyncLoadBarrier.addTask((AsyncLoadObject) asyncProxy); 202 | } 203 | // 返回对象 204 | return asyncProxy; 205 | } 206 | } 207 | 208 | /** 209 | * 取得范性信息 210 | * 211 | * @param cls 212 | * @param i 213 | * @return 214 | */ 215 | private Class getGenericClass(ParameterizedType parameterizedType, int i) { 216 | Object genericClass = parameterizedType.getActualTypeArguments()[i]; 217 | if (genericClass instanceof ParameterizedType) { // 处理多级泛型 218 | return (Class) ((ParameterizedType) genericClass).getRawType(); 219 | } else if (genericClass instanceof GenericArrayType) { // 处理数组泛型 220 | return (Class) ((GenericArrayType) genericClass).getGenericComponentType(); 221 | } else { 222 | return (Class) genericClass; 223 | } 224 | } 225 | 226 | // ===================== setter / getter ============================= 227 | 228 | public void setExecutor(AsyncLoadExecutor executor) { 229 | this.executor = executor; 230 | } 231 | 232 | public void setConfig(AsyncLoadConfig config) { 233 | this.config = config; 234 | } 235 | 236 | /** 237 | * @return the executor 238 | */ 239 | public AsyncLoadExecutor getExecutor() { 240 | return executor; 241 | } 242 | 243 | /** 244 | * @return the config 245 | */ 246 | public AsyncLoadConfig getConfig() { 247 | return config; 248 | } 249 | 250 | /* (non-Javadoc) 251 | * @see java.lang.Object#toString() 252 | */ 253 | @Override 254 | public String toString() { 255 | return "AsyncLoadTemplate [executor=" + executor + ", config=" + config + "]"; 256 | } 257 | 258 | } 259 | -------------------------------------------------------------------------------- /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/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 org.junit.Test; 10 | 11 | import com.alibaba.asyncload.domain.AsyncLoadTestModel; 12 | import com.alibaba.asyncload.domain.AsyncLoadTestService; 13 | import com.alibaba.asyncload.impl.AsyncLoadEnhanceProxy; 14 | import com.alibaba.asyncload.impl.enums.PoolRejectHandleMode; 15 | 16 | import junit.framework.Assert; 17 | 18 | public class AsyncLoadProxyTest extends BaseAsyncLoadNoRunTest { 19 | 20 | @Resource(name = "asyncLoadTestService") 21 | private AsyncLoadTestService asyncLoadTestService; 22 | 23 | @Test 24 | public void testProxy() { 25 | // 初始化config 26 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); 27 | // 初始化executor 28 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 29 | executor.initital(); 30 | // 初始化proxy 31 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 32 | proxy.setService(asyncLoadTestService); 33 | proxy.setConfig(config); 34 | proxy.setExecutor(executor); 35 | // 执行测试 36 | AsyncLoadTestService service = proxy.getProxy(); 37 | AsyncLoadTestModel model1 = service.getRemoteModel("first", 1000); // 每个请求sleep 38 | // 1000ms 39 | AsyncLoadTestModel model2 = service.getRemoteModel("two", 1000); // 每个请求sleep 40 | // 1000ms 41 | AsyncLoadTestModel model3 = service.getRemoteModel("three", 1000); // 每个请求sleep 42 | // 1000ms 43 | 44 | long start = 0, end = 0; 45 | start = System.currentTimeMillis(); 46 | System.out.println(model1.getDetail()); 47 | end = System.currentTimeMillis(); 48 | Assert.assertTrue((end - start) > 500l); // 第一次会阻塞, 响应时间会在1000ms左右 49 | 50 | start = System.currentTimeMillis(); 51 | System.out.println(model2.getDetail()); 52 | end = System.currentTimeMillis(); 53 | Assert.assertTrue((end - start) < 500l); // 第二次不会阻塞,因为第一个已经阻塞了1000ms 54 | 55 | start = System.currentTimeMillis(); 56 | System.out.println(model3.getDetail()); 57 | end = System.currentTimeMillis(); 58 | Assert.assertTrue((end - start) < 500l); // 第三次不会阻塞,因为第一个已经阻塞了1000ms 59 | 60 | // 销毁executor 61 | executor.destory(); 62 | } 63 | 64 | @Test 65 | public void testProxy_timeout() { 66 | // 初始化config 67 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 100l); // 设置超时时间为300ms 68 | // 初始化executor 69 | AsyncLoadExecutor executor = new AsyncLoadExecutor(10, 100); 70 | executor.initital(); 71 | // 初始化proxy 72 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 73 | proxy.setService(asyncLoadTestService); 74 | proxy.setConfig(config); 75 | proxy.setExecutor(executor); 76 | 77 | AsyncLoadTestService service = proxy.getProxy(); 78 | AsyncLoadTestModel model1 = service.getRemoteModel("first", 1000); // 每个请求sleep 79 | // 1000ms 80 | AsyncLoadTestModel model2 = service.getRemoteModel("two", 200); // 每个请求sleep 81 | // 1000ms 82 | 83 | long start = 0, end = 0; 84 | start = System.currentTimeMillis(); 85 | try { 86 | System.out.println(model1.getDetail()); 87 | Assert.fail(); // 不会走到这一步 88 | } catch (Exception e) { // TimeoutException异常 89 | System.out.println(e); 90 | } 91 | end = System.currentTimeMillis(); 92 | Assert.assertTrue((end - start) < 500l); // 会超时 93 | 94 | start = System.currentTimeMillis(); 95 | try { 96 | System.out.println(model2.getDetail()); 97 | } catch (Exception e) { 98 | Assert.fail(); // 不会走到这一步 99 | } 100 | end = System.currentTimeMillis(); 101 | Assert.assertTrue((end - start) < 500l); // 不会超时 102 | } 103 | 104 | @Test 105 | public void testProxy_block_reject() { 106 | // 初始化config 107 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); // 设置超时时间为300ms 108 | // 初始化executor 109 | AsyncLoadExecutor executor = new AsyncLoadExecutor(8, 2, PoolRejectHandleMode.REJECT); // 设置为拒绝,8个工作线程,2个等待队列 110 | executor.initital(); 111 | // 初始化proxy 112 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 113 | proxy.setService(asyncLoadTestService); 114 | proxy.setConfig(config); 115 | proxy.setExecutor(executor); 116 | 117 | AsyncLoadTestService service = proxy.getProxy(); 118 | ExecutorService executeService = Executors.newFixedThreadPool(10); 119 | long start = 0, end = 0; 120 | start = System.currentTimeMillis(); 121 | try { 122 | for (int i = 0; i < 10; i++) { // 创建10个任务 123 | final AsyncLoadTestModel model = service.getRemoteModel("first:" + i, 1000); // 每个请求sleep 124 | // 1000ms 125 | executeService.submit(new Runnable() { 126 | 127 | @Override 128 | public void run() { 129 | System.out.println(model.getDetail()); 130 | } 131 | }); 132 | } 133 | } catch (RejectedExecutionException e) { // 不会出现reject 134 | Assert.fail(); 135 | } 136 | 137 | try { 138 | final AsyncLoadTestModel model = service.getRemoteModel("first:" + 11, 1000); // 创建第11个任务,会出现reject异常 139 | executeService.submit(new Runnable() { 140 | 141 | @Override 142 | public void run() { 143 | System.out.println(model.getDetail()); 144 | } 145 | }); 146 | 147 | Assert.fail();// 不会走到这一步 148 | } catch (RejectedExecutionException e) { 149 | System.out.println(e);// 会出现reject 150 | } 151 | 152 | try { 153 | Thread.sleep(2000l); 154 | } catch (InterruptedException e) { 155 | Assert.fail(); 156 | } 157 | executeService.shutdown(); 158 | end = System.currentTimeMillis(); 159 | System.out.println(end - start); 160 | } 161 | 162 | @Test 163 | public void testProxy_block_reject_noQueue() { 164 | // 初始化config 165 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); // 设置超时时间为3000ms 166 | // 初始化executor 167 | AsyncLoadExecutor executor = new AsyncLoadExecutor(2, 0, PoolRejectHandleMode.REJECT); // 设置为拒绝 168 | executor.initital(); 169 | // 初始化proxy 170 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 171 | proxy.setService(asyncLoadTestService); 172 | proxy.setConfig(config); 173 | proxy.setExecutor(executor); 174 | 175 | AsyncLoadTestService service = proxy.getProxy(); 176 | ExecutorService executeService = Executors.newFixedThreadPool(10); 177 | long start = 0, end = 0; 178 | start = System.currentTimeMillis(); 179 | try { 180 | for (int i = 0; i < 5; i++) { // 创建5个任务 181 | final AsyncLoadTestModel model = service.getRemoteModel("first:" + i, 1000); // 每个请求sleep 182 | // 1000ms 183 | executeService.submit(new Runnable() { 184 | 185 | @Override 186 | public void run() { 187 | System.out.println(model.getDetail()); 188 | } 189 | }); 190 | } 191 | 192 | Assert.fail(); // 不会走到这一步 193 | } catch (RejectedExecutionException e) { // 会出现reject 194 | System.out.println(e);// 会出现reject 195 | } 196 | 197 | try { 198 | Thread.sleep(2000l); 199 | } catch (InterruptedException e) { 200 | Assert.fail(); 201 | } 202 | executeService.shutdown(); 203 | end = System.currentTimeMillis(); 204 | System.out.println(end - start); 205 | } 206 | 207 | @Test 208 | public void testProxy_block_callerRun() { 209 | // 初始化config 210 | AsyncLoadConfig config = new AsyncLoadConfig(3 * 1000l); // 设置超时时间为3000ms 211 | // 初始化executor 212 | AsyncLoadExecutor executor = new AsyncLoadExecutor(1, 0, PoolRejectHandleMode.CALLERRUN); // 设置为caller线程运行模式,10个工作线程,0个等待队列 213 | executor.initital(); 214 | // 初始化proxy 215 | AsyncLoadEnhanceProxy proxy = new AsyncLoadEnhanceProxy(); 216 | proxy.setService(asyncLoadTestService); 217 | proxy.setConfig(config); 218 | proxy.setExecutor(executor); 219 | 220 | AsyncLoadTestService service = proxy.getProxy(); 221 | ExecutorService executeService = Executors.newFixedThreadPool(2); 222 | long start = 0, end = 0; 223 | start = System.currentTimeMillis(); 224 | try { 225 | for (int i = 0; i < 3; i++) { // 创建10个任务 226 | final AsyncLoadTestModel model = service.getRemoteModel("first:" + i, 1000); // 每个请求sleep 227 | // 1000ms 228 | executeService.submit(new Runnable() { 229 | 230 | @Override 231 | public void run() { 232 | System.out.println(model.getDetail()); 233 | } 234 | }); 235 | } 236 | 237 | Thread.sleep(4000l); 238 | } catch (RejectedExecutionException e) { // 不会出现reject 239 | Assert.fail(); 240 | } catch (InterruptedException e) { 241 | Assert.fail(); 242 | } 243 | 244 | executeService.shutdown(); 245 | end = System.currentTimeMillis(); 246 | System.out.println(end - start); 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/main/java/com/alibaba/asyncload/impl/annotation/AsyncAnnotationParserFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * AsyncAnnotationParserFactory.java 3 | * author: yujiakui 4 | * 2018年4月17日 5 | * 下午4:26:50 6 | */ 7 | package com.alibaba.asyncload.impl.annotation; 8 | 9 | import java.lang.reflect.Method; 10 | import java.text.MessageFormat; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.aop.framework.AopProxyUtils; 17 | import org.springframework.beans.BeansException; 18 | import org.springframework.beans.factory.InitializingBean; 19 | import org.springframework.beans.factory.annotation.Value; 20 | import org.springframework.context.ApplicationContext; 21 | import org.springframework.context.ApplicationContextAware; 22 | import org.springframework.stereotype.Component; 23 | import org.springframework.util.CollectionUtils; 24 | 25 | import com.alibaba.asyncload.AsyncLoadConfig; 26 | import com.alibaba.asyncload.AsyncLoadExecutor; 27 | import com.alibaba.asyncload.AsyncLoadMethodMatch; 28 | import com.alibaba.asyncload.impl.AsyncLoadPerl5RegexpMethodMatcher; 29 | import com.alibaba.asyncload.impl.exceptions.AsyncLoadException; 30 | import com.alibaba.asyncload.impl.template.AsyncLoadTemplate; 31 | import com.alibaba.asyncload.impl.util.MethodFilterUtil; 32 | import com.google.common.collect.Lists; 33 | import com.google.common.collect.Maps; 34 | 35 | /** 36 | * @author yujiakui 37 | * 38 | * 下午4:26:50 39 | * 40 | * 异步注解解析 41 | */ 42 | @Component 43 | public class AsyncAnnotationParserFactory implements ApplicationContextAware, InitializingBean { 44 | 45 | /** 日志 */ 46 | private final static Logger LOGGER = LoggerFactory 47 | .getLogger(AsyncAnnotationParserFactory.class); 48 | 49 | /** spring 应用程序上下文 */ 50 | private ApplicationContext applicationContext; 51 | 52 | /** 类中方法对应的异步模板表:String对应的类全名 */ 53 | private Map> methodAsyncTemplateTable = Maps 54 | .newConcurrentMap(); 55 | 56 | /** 类中的方法配置执行器,其中String对应的是类全名 */ 57 | private Map> methodConfExecMap = Maps.newConcurrentMap(); 58 | 59 | /** 从配置文件中读取,如果没有读取到默认是20 */ 60 | @Value("${asyncLoad.poolSize:20}") 61 | private int poolSize; 62 | 63 | /** 线程池大小,默认是100 */ 64 | @Value("${aysncLoad.queueSize:100}") 65 | private int queueSize; 66 | 67 | /** 线程池拒绝策略,默认是在主线程中执行 */ 68 | @Value("${aysncLoad.rejectPolicy:CALLERRUN}") 69 | private String rejectPolicy; 70 | 71 | /* (non-Javadoc) 72 | * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() 73 | */ 74 | @Override 75 | public void afterPropertiesSet() throws Exception { 76 | Map asyncLoadBeanMap = applicationContext 77 | .getBeansWithAnnotation(AsyncClassDef.class); 78 | 79 | // 遍历对应的对象填充对应的map 80 | for (Object beanObj : asyncLoadBeanMap.values()) { 81 | // 因为被拦截器拦住,使用cglib进行代理,所有需要获得对应的原始类 82 | Class originBeanClass = AopProxyUtils.ultimateTargetClass(beanObj); 83 | 84 | // 解析类上面的注解 85 | AsyncLoadExecutor asyncLoadExecutor = parseClassAnnotation(originBeanClass); 86 | // 解析方法上面的注解 87 | parseMethodAnnotation(originBeanClass, asyncLoadExecutor); 88 | } 89 | 90 | LOGGER.info(MessageFormat.format( 91 | "异步并行加载解析对应的结果methodAsyncTemplateTable={0},methodConfExecMap={1}", 92 | methodAsyncTemplateTable, methodConfExecMap)); 93 | } 94 | 95 | /** 96 | * 解析方法注解 97 | * 98 | * @param originBeanClasss 99 | */ 100 | private void parseMethodAnnotation(Class originBeanClasss, 101 | AsyncLoadExecutor parentExecutor) { 102 | 103 | Map asyncLoadTemplateMap = methodAsyncTemplateTable 104 | .get(originBeanClasss.getName()); 105 | if (null != asyncLoadTemplateMap) { 106 | throw new AsyncLoadException( 107 | MessageFormat.format("类名className={0}对应的配置在table中已经存在,table={1}", 108 | originBeanClasss.getName(), methodAsyncTemplateTable)); 109 | } else { 110 | asyncLoadTemplateMap = Maps.newConcurrentMap(); 111 | } 112 | Method[] methods = originBeanClasss.getMethods(); 113 | for (Method method : methods) { 114 | // 排除一些方法,排除Object对应的方法,仅仅需要public方法 115 | if (MethodFilterUtil.filterMethod(method)) { 116 | continue; 117 | } 118 | 119 | // 方法上的注解 120 | AsyncMethodDef asyncMethod = method.getDeclaredAnnotation(AsyncMethodDef.class); 121 | if (null != asyncMethod) { 122 | 123 | AsyncLoadTemplate asyncLoadTemplate = assembleAsyncLoadTemplate(asyncMethod, 124 | parentExecutor, new String[] { method.getName() }); 125 | asyncLoadTemplateMap.put(method, asyncLoadTemplate); 126 | } 127 | } 128 | 129 | if (!CollectionUtils.isEmpty(asyncLoadTemplateMap)) { 130 | methodAsyncTemplateTable.put(originBeanClasss.getName(), asyncLoadTemplateMap); 131 | } 132 | } 133 | 134 | /** 135 | * 组装异步加载模板 136 | * 137 | * @param asyncMethod 138 | * @param parentExecutor 139 | * @return 140 | */ 141 | private AsyncLoadTemplate assembleAsyncLoadTemplate(AsyncMethodDef asyncMethod, 142 | AsyncLoadExecutor parentExecutor, String[] overrideMethodMatchRegexs) { 143 | 144 | AsyncLoadConfig asyncLoadConfig = new AsyncLoadConfig(); 145 | asyncLoadConfig.setDefaultTimeout(asyncMethod.timeout()); 146 | asyncLoadConfig.setNeedThreadLocalSupport(asyncMethod.inheritThreadLocal()); 147 | AsyncLoadPerl5RegexpMethodMatcher asyncLoadPerl5RegexpMethodMatcher = new AsyncLoadPerl5RegexpMethodMatcher(); 148 | if (null == overrideMethodMatchRegexs || overrideMethodMatchRegexs.length == 0) { 149 | asyncLoadPerl5RegexpMethodMatcher.setPatterns(asyncMethod.methodMatchRegex()); 150 | asyncLoadPerl5RegexpMethodMatcher 151 | .setExcludedPatterns(asyncMethod.excludeMethodMatchRegex()); 152 | } else { 153 | asyncLoadPerl5RegexpMethodMatcher.setPatterns(overrideMethodMatchRegexs); 154 | } 155 | Map methodMatchMap = Maps.newHashMap(); 156 | methodMatchMap.put(asyncLoadPerl5RegexpMethodMatcher, asyncMethod.timeout()); 157 | asyncLoadConfig.setMatches(methodMatchMap); 158 | 159 | AsyncLoadExecutor methodAsyncExecutor = parentExecutor; 160 | AsyncThreadPoolConfig methodAsyncThreadPoolConfig = asyncMethod.methodThreadPoolConf(); 161 | if (methodAsyncThreadPoolConfig.effect()) { 162 | methodAsyncExecutor = new AsyncLoadExecutor(); 163 | methodAsyncExecutor.setAcceptCount(methodAsyncThreadPoolConfig.queueSize()); 164 | methodAsyncExecutor.setMode(methodAsyncThreadPoolConfig.rejectPolicy()); 165 | methodAsyncExecutor.setPoolSize(methodAsyncThreadPoolConfig.poolSize()); 166 | // TODO 调用初始化生成线程池 167 | // methodAsyncExecutor.initital(); 168 | } 169 | 170 | AsyncLoadTemplate asyncLoadTemplate = new AsyncLoadTemplate(); 171 | asyncLoadTemplate.setConfig(asyncLoadConfig); 172 | asyncLoadTemplate.setExecutor(methodAsyncExecutor); 173 | 174 | return asyncLoadTemplate; 175 | } 176 | 177 | /** 178 | * 类上面的注解解析 179 | * 180 | * @param originBeanClass 181 | */ 182 | private AsyncLoadExecutor parseClassAnnotation(Class originBeanClass) { 183 | // 获取AsyncClass注解 184 | AsyncClassDef asyncClass = originBeanClass.getAnnotation(AsyncClassDef.class); 185 | String classFullName = originBeanClass.getName(); 186 | // 根据类名获得对应的映射结果 187 | List asyncLoadTemplates = methodConfExecMap.get(classFullName); 188 | if (null != asyncLoadTemplates) { 189 | throw new AsyncLoadException(MessageFormat.format( 190 | "类名className={0}对应的配置在table中已经存在,table={1}", classFullName, methodConfExecMap)); 191 | } else { 192 | asyncLoadTemplates = Lists.newArrayList(); 193 | } 194 | AsyncThreadPoolConfig asyncThreadPoolConfig = asyncClass.classThreadPoolConf(); 195 | AsyncLoadExecutor asyncLoadExecutor = getClassThreadPoolConfig(asyncThreadPoolConfig); 196 | AsyncMethodDef[] asyncMethods = asyncClass.asyncMethods(); 197 | 198 | if (null != asyncMethods) { 199 | for (AsyncMethodDef asyncMethod : asyncMethods) { 200 | // 获得模板 201 | AsyncLoadTemplate asyncLoadTemplate = assembleAsyncLoadTemplate(asyncMethod, 202 | asyncLoadExecutor, null); 203 | asyncLoadTemplates.add(asyncLoadTemplate); 204 | } 205 | } 206 | 207 | if (!CollectionUtils.isEmpty(asyncLoadTemplates)) { 208 | methodConfExecMap.put(classFullName, asyncLoadTemplates); 209 | } 210 | return asyncLoadExecutor; 211 | } 212 | 213 | /** 214 | * 获取类级别的线程池配置 215 | * 216 | * 如果类上面配置的失效,则使用默认全局的 217 | * 218 | * @param asyncThreadPoolConfig 219 | * @return 220 | */ 221 | private AsyncLoadExecutor getClassThreadPoolConfig( 222 | AsyncThreadPoolConfig asyncThreadPoolConfig) { 223 | AsyncLoadExecutor asyncLoadExecutor = new AsyncLoadExecutor(); 224 | if (asyncThreadPoolConfig.effect()) { 225 | asyncLoadExecutor.setAcceptCount(asyncThreadPoolConfig.queueSize()); 226 | asyncLoadExecutor.setMode(asyncThreadPoolConfig.rejectPolicy()); 227 | asyncLoadExecutor.setPoolSize(asyncThreadPoolConfig.poolSize()); 228 | } else { 229 | asyncLoadExecutor.setAcceptCount(queueSize); 230 | asyncLoadExecutor.setMode(rejectPolicy); 231 | asyncLoadExecutor.setPoolSize(poolSize); 232 | } 233 | return asyncLoadExecutor; 234 | } 235 | 236 | /* (non-Javadoc) 237 | * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) 238 | */ 239 | @Override 240 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 241 | this.applicationContext = applicationContext; 242 | } 243 | 244 | /** 245 | * @return the methodAsyncTemplateTable 246 | */ 247 | public Map> getMethodAsyncTemplateTable() { 248 | return methodAsyncTemplateTable; 249 | } 250 | 251 | /** 252 | * @return the methodConfExecMap 253 | */ 254 | public Map> getMethodConfExecMap() { 255 | return methodConfExecMap; 256 | } 257 | 258 | /** 259 | * @param methodConfExecMap 260 | * the methodConfExecMap to set 261 | */ 262 | public void setMethodConfExecMap(Map> methodConfExecMap) { 263 | this.methodConfExecMap = methodConfExecMap; 264 | } 265 | 266 | } 267 | -------------------------------------------------------------------------------- /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/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 | --------------------------------------------------------------------------------