/* * Copyright 2008 biaoping.yin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.frameworkset.spi.async; import java.lang.reflect.InvocationTargetException; import java.util.concurrent.FutureTask; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import org.frameworkset.spi.ApplicationContext; import org.frameworkset.spi.BaseSPIManager2; import org.frameworkset.spi.assemble.ProMap; import org.frameworkset.spi.async.annotation.Result; import org.frameworkset.util.TimeUtil; /** * <p> * Title: AsyncCall.java * </p> * <p> * Description: 执行服务的异步调用 * </p> * <p> * bboss workgroup * </p> * <p> * Copyright (c) 2007 * </p> * * @Date 2011-4-21 上午11:06:42 * @author biaoping.yin * @version 1.0 */ public class AsyncCall { private static Logger log = Logger.getLogger(AsyncCall.class); // static java.util.concurrent.ThreadPoolExecutor executor = null; private java.util.concurrent.ThreadPoolExecutor callexecutor = null; private java.util.concurrent.ThreadPoolExecutor callbackexecutor = null; private Object lock = new Object(); private boolean started = false; private CallHandler callHandler; private CallBackHandler callBackHandler; /** * 请求调用堆栈 */ private LinkedBlockingQueue<CallService> callblockqueue = new java.util.concurrent.LinkedBlockingQueue<CallService>( BaseSPIManager2.getIntProperty( "component.asynccall.block.size", 200)); /** * 请求响应回调处理堆栈 */ private LinkedBlockingQueue<CallService> callbackblockqueue = new java.util.concurrent.LinkedBlockingQueue<CallService>( BaseSPIManager2.getIntProperty( "component.asynccallback.block.size", 200)); public void start() { if (this.started) return; synchronized (lock) { if (this.started) return; initCallExecutor(); initCallBackExecutor(); callHandler = new CallHandler(); new Thread(this.callHandler, "callHandler").start(); callBackHandler = new CallBackHandler(); new Thread(this.callBackHandler, "callBackHandler").start(); this.started = true; } } public void stop() { synchronized (lock) { if (!this.started) return; stopCallExecutor(); stopCallBackExecutor(); started = false; } } private void stopCallExecutor() { if (this.callexecutor != null) this.callexecutor.shutdown(); } private void stopCallBackExecutor() { if (this.callbackexecutor != null) this.callbackexecutor.shutdown(); } private void initCallExecutor() { ProMap proMap = BaseSPIManager2 .getMapProperty("component.asynccall.threadpool"); if (proMap == null || proMap.size() == 0) { /** * public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, * long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> * workQueue, RejectedExecutionHandler handler) */ callexecutor = new java.util.concurrent.ThreadPoolExecutor(5, 20, 40, TimeUnit.SECONDS, new java.util.concurrent.LinkedBlockingQueue<Runnable>( BaseSPIManager2 .getIntProperty( "component.asynccall.block.size", 200) / 2), new CallerRunsPolicy()); } else { String timeUnit = proMap.getString("timeUnit", "TimeUnit.SECONDS"); TimeUnit timeUnit_ = TimeUtil.getTimeUnitByName(timeUnit, TimeUnit.SECONDS); callexecutor = new java.util.concurrent.ThreadPoolExecutor(proMap .getInt("corePoolSize", 5), proMap.getInt( "maximumPoolSize", 20), proMap.getInt("keepAliveTime", 40), timeUnit_, new java.util.concurrent.LinkedBlockingQueue<Runnable>( BaseSPIManager2 .getIntProperty( "component.asynccall.block.size", 200) / 2), new CallerRunsPolicy()); } } private void initCallBackExecutor() { ProMap proMap = BaseSPIManager2 .getMapProperty("component.asynccallback.threadpool"); if (proMap == null || proMap.size() == 0) { /** * public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, * long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> * workQueue, RejectedExecutionHandler handler) */ callbackexecutor = new java.util.concurrent.ThreadPoolExecutor( 5, 20, 40, TimeUnit.SECONDS, new java.util.concurrent.LinkedBlockingQueue<Runnable>( ApplicationContext .getApplicationContext() .getIntProperty( "component.asynccallback.block.size", 200) / 2), new CallerRunsPolicy()); } else { String timeUnit = proMap.getString("timeUnit", "TimeUnit.SECONDS"); TimeUnit timeUnit_ = TimeUtil.getTimeUnitByName(timeUnit, TimeUnit.SECONDS); callbackexecutor = new java.util.concurrent.ThreadPoolExecutor( proMap.getInt("corePoolSize", 5), proMap.getInt("maximumPoolSize", 20), proMap.getInt("keepAliveTime", 40), timeUnit_, new java.util.concurrent.LinkedBlockingQueue<Runnable>( ApplicationContext .getApplicationContext() .getIntProperty( "component.asynccallback.block.size", 200) / 2), new CallerRunsPolicy()); } } public boolean started() { return this.started; } public void putCallService(CallService callService) throws InterruptedException { callblockqueue.put(callService); } public void putCallBackService(CallService callService) throws InterruptedException { this.callbackblockqueue.put(callService); } public Object runCallService(CallService task) throws Exception { if (!this.started()) throw new AsyncCallException("异步调用服务已经被停止,拒绝接受新的异步服务调用"); if (task != null) { try { /** * 如果需要返回结果,那么检测是否回调方式,如果不是回调方式,那么采用阻塞主线程模式,如果是采用异步调用方式 * 如果不需要返回结果,那么直接采用异步调用方式 */ if (task.getAsyncMethod().getAsyncResultMode() == Result.YES) { if (task.getAsyncMethod().getAsyncCallback() == null) { if (task.getAsyncMethod().getAsyncTimeout() > 0) { FutureTask f = new FutureTask(task); callexecutor.execute(f); return f.get(task.getAsyncMethod() .getAsyncTimeout(), TimeUnit.MICROSECONDS); } else // 这种不设置超时直接阻塞的方式没有实际意义,与同步调用一致 { FutureTask f = new FutureTask(task); callexecutor.execute(f); return f.get(); } } else {//有回调函数则异步处理,交给工作队列异步处理 this.putCallBackService(task); } } else {//不需要返回值则异步处理,交给工作队列异步处理,防止大并发访问资源被耗尽 this.putCallService(task); } } catch (Exception e) { throw e; } return null; } else throw new AsyncCallException("异步服务调用失败:服务为null"); } /** * 不需要返回结果的模式,也没有回调函数,可以指定超时时间,如果没有指定则run方法中同步条用 * 否则异步调用,超时时报异常记录日志(这种超时没有特别的意义,只是告诉系统说明服务之星超过摸个时间了) * <p>Title: AsyncCall.java</p> * <p>Description: </p> * <p>bboss workgroup</p> * <p>Copyright (c) 2007</p> * @Date 2011-4-21 下午03:58:56 * @author biaoping.yin * @version 1.0 */ public static class AsynRunnable implements Runnable { CallService task; AsynRunnable(CallService task) { this.task = task; } public void run() { try { if(task.getAsyncMethod().getAsyncTimeout() <= 0) { task.call(); } else { FutureTask t = new FutureTask(task); new Thread(t).start(); t.get(task.getAsyncMethod().getAsyncTimeout(), TimeUnit.MICROSECONDS); } } catch (Exception e) { log.error(e.getMessage(),e); } } } public static class AsynCallbackRunnable implements Runnable { CallService task; AsynCallbackRunnable(CallService task) { this.task = task; } public void run() { try { if(task.getAsyncMethod().getAsyncTimeout() <= 0) { final Object ret = task.call(); /** * 对调用结果采用异步方式进行回调处理 */ new Thread(new Runnable(){ public void run() { task.getCallBackService().getCallBack().handleResult(ret); } }).start(); } else { FutureTask t = new FutureTask(task); new Thread(t).start(); final Object ret = t.get(task.getAsyncMethod().getAsyncTimeout(), TimeUnit.MICROSECONDS); /** * 对调用结果采用异步方式进行回调处理 */ new Thread(new Runnable(){ public void run() { task.getCallBackService().getCallBack().handleResult(ret); } }).start(); } } catch (InvocationTargetException e) { final Throwable throwable = e.getTargetException(); new Thread(new Runnable(){ public void run() { task.getCallBackService().getCallBack().handleError(throwable); } }).start(); } catch (Exception e) { final Throwable throwable = e; new Thread(new Runnable(){ public void run() { task.getCallBackService().getCallBack().handleError(throwable); } }).start(); } } } class CallHandler implements Runnable { public void run() { CallService callService = null; while (true) { // if (!AsyncCall.this.started()) // break; try { callService = callblockqueue.take(); callexecutor.execute(new AsynRunnable(callService)); } catch (Exception e) { log.error(e.getMessage(),e); continue; } } } } class CallBackHandler implements Runnable { public void run() { CallService callService = null; while (true) { // if (!AsyncCall.this.started()) // break; try { callService = callbackblockqueue.take(); callbackexecutor.execute(new AsynCallbackRunnable(callService)); } catch (Exception e) { log.error(e.getMessage(),e); continue; } } } } }