GitHub - alibaba/asyncload: 阿里巴巴异步并行加载工具(依赖字节码技术)
扩展异步并行调度框架asyncLoad支持注解配置

实现原理

  • 原理:线程池 + Future + Cglib 结合的方式来实现
  • 优点:正好是异步并行基本实现方式对应的缺点,不需要基础开发人员了解更多异步并行实现方式,可以让基础开发人员还是按照原来开发串行执行代码一样进行开发,唯一的不同就是在需要异步并行执行的方法上增加对应的配置(xml,注解等方式);
  • 缺点:cglib 本身的方式带来的缺点(通过实现对应目标类的子类来实现动态代理,并且可以在生成子类的时候在对应方法上进行拦截,增强子类方法的功能),但是这种方式的代理本身不支持 final 类(因为 final 类不支持生成对应的子类),因此对应的像基元类型就不支持;灵活性不如基础的好;

这里正好设计到多个知识点, Spring AOP 和 AspectJ 注解集成下的源码解读

流程图

525

使用方式

  • 入口,开启异步调用
@Component
@AsyncClassDef
public class AsyncLoadAnnotationTestServiceImpl extends AsyncLoadTestServiceImpl {
 
	@Override
	@AsyncMethodDef(timeout = 10)
	public AsyncLoadTestModel getRemoteModel(String name, long sleep) {
		return super.getRemoteModel(name, sleep);
	}
}
  • 实际业务代码
@Component  
@EnableAsyncClass  
public class AsyncLoadAnnotationMultiMethodTest {
 
    @Autowired
    private AsyncLoadAnnotationTestServiceImpl asyncLoadAnnotationTestServiceImpl;
 
    @EnableAsyncMethod
    public List<AsyncLoadTestModel> multiHandler(String name, long sleep) {
 
        List<AsyncLoadTestModel> results = Lists.newArrayList();
        for (int i = 0; i < 5; i++) {
            AsyncLoadTestModel model = asyncLoadAnnotationTestServiceImpl.getRemoteModel(name,
                    sleep);
 
            results.add(model);
        }
        return results;
    }
 
}
 
  • 验证
public static void main(String[] args) {  
   AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(  
         "com.alibaba.asyncload.impl.annotation", "com.alibaba.asyncload.annotation",  
         "com.alibaba.asyncload.domain");  
   System.out.println(annotationConfigApplicationContext.getBeanDefinitionNames());  
  
   /*AsyncLoadHandlerAop aop = annotationConfigApplicationContext  
         .getBean(AsyncLoadHandlerAop.class);*/  
   // 执行测试  
   AsyncLoadAnnotationTestServiceImpl service = annotationConfigApplicationContext  
         .getBean(AsyncLoadAnnotationTestServiceImpl.class);  
   AsyncLoadTestModel model1 = service.getRemoteModel("first", 1000); // 每个请求sleep  
                                                      // 1000ms   AsyncLoadTestModel model2 = service.getRemoteModel("two", 1000); // 每个请求sleep  
                                                      // 1000ms   AsyncLoadTestModel model3 = service.getRemoteModel("three", 1000); // 每个请求sleep  
                                                      // 1000ms  
   long start = 0, end = 0;  
   start = System.currentTimeMillis();  
   System.out.println(model1.getDetail());  
   end = System.currentTimeMillis();  
   System.out.println("costTime:" + (end - start));  
   Assert.assertTrue((end - start) > 500l); // 第一次会阻塞, 响应时间会在1000ms左右  
  
   start = System.currentTimeMillis();  
   System.out.println(model2.getDetail());  
   end = System.currentTimeMillis();  
   System.out.println("costTime:" + (end - start));  
   Assert.assertTrue((end - start) < 500l); // 第二次不会阻塞,因为第一个已经阻塞了1000ms  
  
   start = System.currentTimeMillis();  
   System.out.println(model3.getDetail());  
   end = System.currentTimeMillis();  
   System.out.println("costTime:" + (end - start));  
   Assert.assertTrue((end - start) < 500l); // 第三次不会阻塞,因为第一个已经阻塞了1000ms  
  
}

借鉴方案

说白了,以上方案就是借用了 AspectJAspect 实现的异步逻辑,如果不希望使用 Spring 来启动,可以直接借用 Spring 的 AspectJProxyFactory
从而创建一个代理类,从而实现异步的调用。
ps: 当然还要魔改一下上面 Alibaba-AsyncLoad 的逻辑

public class AsyncLoadAnnotationDirectTest {  
      
    public static void main(String[] args) {  
      
        AsyncLoadAnnotationTestServiceImpl service = new AsyncLoadAnnotationTestServiceImpl();  
        AspectJProxyFactory factory = new AspectJProxyFactory(service);  
        factory.addAspect(AsyncLoadHandlerAdvice.class);  
        AsyncLoadTestService proxy = factory.getProxy();  
        AsyncLoadTestModel remoteModel = proxy.getRemoteModel("2", 33L);  
        System.out.println();  
    }  
}