用Annotation,Future,动态代理实现自己的JAVA方法运行超时应用
2011-04-08 12:50
1251 查看
设置一个方法的执行超时,通常用守护线程或FUTURE接口来实现,但是每次要写一堆来实现,这里用Annotation和动态代理来实现,简化开发。
设计原则:将需要超时的方法标记为@Timeout("5000"),表示该方法执行超过5000MS时,将抛出超时异常。
在系统加载类时,通过指定package或目录扫描类,找出有@Timeout标记的方法,将其类动态代理。在调用该方法时通过代理类来执行达到超时的效果。
本人一共设计了几个类,如下图:
@Timeout,关于Annotatiion的定义以及说明本文不做阐述了。
1.LocalTimeoutException.java
2.TimeoutBean,用来记录标记了@Timeout的方法以及其所属类对象
3.TimeoutFactory.java,用来扫描类和生成代理类
4.TimeoutHandler.java,实现Future接口(java.util.concurrent)功能,也就是超时
5.TimeoutCallable.java,Future接口所学的Callable
6.TimeoutTest.java,效果测试类与接口类
调用演示:仔细观察几个方法,你会发现其输出的结果又所不同。
如:execute()方法在超时后就不会执行后面的语句,而connect()方法即使超时后还是会执行后面的语句,并且会抛出InterruptedException,而execute()方法只会抛出LocalTimeoutException.
print()是普通方法。test()方法则不会抛出任何异常。
通常采用execute()方法这种写法就可以达到我们想要的效果了。。。
设计原则:将需要超时的方法标记为@Timeout("5000"),表示该方法执行超过5000MS时,将抛出超时异常。
在系统加载类时,通过指定package或目录扫描类,找出有@Timeout标记的方法,将其类动态代理。在调用该方法时通过代理类来执行达到超时的效果。
本人一共设计了几个类,如下图:
@Timeout,关于Annotatiion的定义以及说明本文不做阐述了。
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Timeout { String value() default "2000"; }
1.LocalTimeoutException.java
public class LocalTimeoutException extends RuntimeException{ /** * */ private static final long serialVersionUID = 1L; public LocalTimeoutException(){ super(); } }
2.TimeoutBean,用来记录标记了@Timeout的方法以及其所属类对象
import java.lang.reflect.Method; import com.system.annotation.Timeout; public class TimeoutBean { private Timeout timeout; private Object object; private Method method; public TimeoutBean(){ } public Timeout getTimeout() { return timeout; } public void setTimeout(Timeout timeout) { this.timeout = timeout; } public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; } }
3.TimeoutFactory.java,用来扫描类和生成代理类
import java.io.File; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.system.annotation.Timeout; public class TimeoutFactory { //一个类可能有多个@Timeout private static Map<String,List<TimeoutBean>> map = new HashMap<String,List<TimeoutBean>>(); static String target = ""; static{ search(); } /** * WEB-INF/classes */ private static void search(){ String classPath = System.getProperty("java.class.path"); target = classPath.split(";")[0]; File file = new File(target); getAll(file); } /** * 这里只是本地测试环境,我的是一个WEB工程,所以在/web-inf/classes目录下面去找,各位可以自行设计成其他扫描方式 * @param file */ private static void getAll(File file){ if(!file.isDirectory()){ if(file.getName().endsWith("class")){ String pkg = file.getAbsolutePath(); pkg = pkg.replaceAll(target.replaceAll("////", "////////"), ""); pkg = pkg.replaceAll("////|//.//$?class$", "."); pkg = pkg.replaceAll("^//.|//.$", ""); if(!map.containsKey(pkg)){ createInstance(pkg); } } }else{ File[] files = file.listFiles(); for(File f : files){ getAll(f); } } } /** * 查找@timeout方法 * @param pkg */ private static void createInstance(String pkg){ try { Class<?> cls = Class.forName(pkg); //System.out.println(cls.getName()); Method[] m = cls.getMethods(); List<TimeoutBean> list = new ArrayList<TimeoutBean>(); for(Method method : m){ if(method.isAnnotationPresent(Timeout.class)){ Timeout to = (Timeout) method.getAnnotation(Timeout.class); TimeoutBean tb = new TimeoutBean(); tb.setTimeout(to); tb.setObject(cls); tb.setMethod(method); list.add(tb); } } if(list.size() > 0){ map.put(pkg, list); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static List<TimeoutBean> getTimeoutBean(String key){ return map.get(key); } public static Object get(Class<?> clazz){ Object obj = null; TimeoutHandler th = new TimeoutHandler(); try { obj = Class.forName(clazz.getCanonicalName()).newInstance(); th.setTarget(obj); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return Proxy.newProxyInstance( TimeoutTest.class.getClassLoader(), TimeoutTest.class.getInterfaces(), th); } }
4.TimeoutHandler.java,实现Future接口(java.util.concurrent)功能,也就是超时
public class TimeoutHandler implements InvocationHandler { private Object target; private TimeoutBean timeoutBean; public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable { // TODO Auto-generated method stub timeoutBean = get(method); Object obj = null; if(timeoutBean != null){ obj = execute(target,arg2,method); }else{ obj = method.invoke(target, arg2); } return obj; } /** * 根据METHOD获取 对应的 TIMEOUTBEAN * @param method * @return */ private TimeoutBean get(Method method){ List<TimeoutBean> list = TimeoutFactory.getTimeoutBean(target.getClass().getName()); for(TimeoutBean tb : list){ if(methodEquals(tb.getMethod(),method)){ return tb; } } return null; } private boolean methodEquals(Method m1,Method m2){ if(!m1.getName().equals(m2.getName())){ return false; } Class<?>[] cls1 = m1.getParameterTypes(); Class<?>[] cls2 = m1.getParameterTypes(); if(cls1.length != cls2.length){ return false; } int len = cls1.length; //防止多态 for(int i = 0; i < len; i++){ Class<?> clazz1 = cls1[i]; Class<?> clazz2 = cls2[i]; if(!clazz1.getName().equals(clazz2.getName())){ return false; } } return true; } private Object execute(Object target,Object[] args,Method method) throws Throwable{ Object ret = null; TimeoutCallable tc = new TimeoutCallable(); tc.setArgs(args); tc.setMethod(method); tc.setTarget(target); ExecutorService executor = Executors.newSingleThreadExecutor(); FutureTask<Object> future = new FutureTask<Object>(tc); executor.execute(future); try { ret = future.get(Integer.parseInt(timeoutBean.getTimeout().value()), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { future.cancel(true); throw new LocalTimeoutException(); } catch (ExecutionException e) { future.cancel(true); throw new LocalTimeoutException(); } catch (TimeoutException e) { future.cancel(true); throw new LocalTimeoutException(); } finally { executor.shutdown(); } return ret; } }
5.TimeoutCallable.java,Future接口所学的Callable
import java.lang.reflect.Method; import java.util.concurrent.Callable; public class TimeoutCallable implements Callable<Object> { private Object[] args; private Method method; private Object target; public Object[] getArgs() { return args; } public void setArgs(Object[] args) { this.args = args; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } @Override public Object call() throws Exception { // TODO Auto-generated method stub return method.invoke(target, args); } }
6.TimeoutTest.java,效果测试类与接口类
import com.system.annotation.Timeout; public class TimeoutTest implements ITimeout { public TimeoutTest() { } @Timeout("2000") public void execute() throws Throwable { System.out.println("execute"); Thread.sleep(3000); System.out.println("complete execute"); } @Override @Timeout("2000") public void test() throws Throwable { // TODO Auto-generated method stub System.out.println("test"); Thread.sleep(1000); System.out.println("complete test"); } @Override @Timeout("2000") public void connect(){ // TODO Auto-generated method stub System.out.println("connect"); try{ Thread.sleep(3000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("complete connect"); } public void print(){ System.out.println("normal method print"); } } //接口 public interface ITimeout { public void execute() throws Throwable; public void test() throws Throwable; public void connect() ; public void print(); }
调用演示:仔细观察几个方法,你会发现其输出的结果又所不同。
如:execute()方法在超时后就不会执行后面的语句,而connect()方法即使超时后还是会执行后面的语句,并且会抛出InterruptedException,而execute()方法只会抛出LocalTimeoutException.
print()是普通方法。test()方法则不会抛出任何异常。
通常采用execute()方法这种写法就可以达到我们想要的效果了。。。
public static void main(String...args) throws Throwable{ ITimeout it = (ITimeout) TimeoutFactory.get(TimeoutTest.class); it.print(); it.test(); it.connect(); it.execute(); }
相关文章推荐
- JAVA动态代理和方法拦截(使用CGLib实现AOP、方法拦截、委托)
- Java动态代理的两种实现方法
- java动态代理对象实现日志的拦截(annotation自定义注解方式)
- Java动态代理的两种实现方法
- java动态代理的实现及原理, 混型应用
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java 动态代理 两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- Java动态代理的两种实现方法
- java中的动态代理----自己手动实现