应用项目大致的体系结构:
    
  
 该异常处理框架满足的要求:
 
    - 完整的异常组织结构
    
- 异常的统一处理
    
- 可配置,受管式,方便使用 
  
完整的异常组织结构:
    - 用户可以方便的定义自己的异常,但所有UncheckedException需要继承BaseAppRuntimeException,所有的checked Exception可以继承BaseAppException,或者需要抛出且不需要check时用WrapperredAppException封装后抛出
    
- 合理地使用checked异常
    
- Exception有唯一的error code,这样用户报告异常后,可以根据异常号找到相应Exception,把exception直接显示给用户也没有太大的意义,如何纪录exception那就是下文讲到的ExceptionHandler的职责了。
    
- 如果是第三方包括jdk中的异常,需要封装成BaseAppException或者BaseAppRuntimeException后抛出 
                                      
   
  
统一的异常处理
异常统一在框架中进行处理,不需要在上层应用的代码中去处理抛出的异常。为了尽量捕捉到所有的异常,将异常处理放在了ActionBroker中,这样凡是action以后抛出的异常都可以捕捉到,因为webservice只是简单的调用action类的方法,一般不会出现异常。当我们捕捉到异常后,需要进行异常处理,定义了ExceptionHandler接口,用接口抽象出异常处理类的具体实现。
 
                         
 
USFContextFactory: 创建ExceptionContext的工厂
 1 package com.ldd600.exception.context;
package com.ldd600.exception.context;
 2
 3
 public class CoreContextFactory
public class CoreContextFactory  {
{
 4 private static CoreContextFactory instance;
    private static CoreContextFactory instance;
 5
 6 private volatile ExceptionContext exceptionContext;
    private volatile ExceptionContext exceptionContext;
 7
 8 private Object exceptionContextLock = new Object();
    private Object exceptionContextLock = new Object();
 9
10
 private CoreContextFactory()
    private CoreContextFactory()  {
{
11
12 }
    }
13
14
 public static synchronized CoreContextFactory getInstance()
    public static synchronized CoreContextFactory getInstance()  {
{
15
 if (null == instance)
        if (null == instance)  {
{
16 instance = new CoreContextFactory();
            instance = new CoreContextFactory();
17 }
        }
18 return instance;
        return instance;
19 }
    }
20
21
 public ExceptionContext getExceptionContext()
    public ExceptionContext getExceptionContext()  {
{
22 ExceptionContext tempExpContext = exceptionContext;
        ExceptionContext tempExpContext = exceptionContext;
23
 if (tempExpContext == null)
        if (tempExpContext == null)  {
{ 
24
 synchronized (exceptionContextLock)
            synchronized (exceptionContextLock)  {
{
25 tempExpContext = exceptionContext;
                tempExpContext = exceptionContext;
26 if (tempExpContext == null)
                if (tempExpContext == null)
27 exceptionContext = tempExpContext = new ExceptionContext();
                    exceptionContext = tempExpContext = new ExceptionContext();
28 }
            }
29 }
        }
30 return tempExpContext;
        return tempExpContext;
31 }
    }
32 }
}
33
 
   
ExceptionContext: 存放全局的exception信息
 
  1 package com.ldd600.exception.context;
package com.ldd600.exception.context;
  2
  3 import java.util.ArrayList;
import java.util.ArrayList;
  4 import java.util.Collection;
import java.util.Collection;
  5 import java.util.Collections;
import java.util.Collections;
  6 import java.util.HashMap;
import java.util.HashMap;
  7 import java.util.List;
import java.util.List;
  8 import java.util.Map;
import java.util.Map;
  9 import java.util.Set;
import java.util.Set;
 10
 11 import org.springframework.util.Assert;
import org.springframework.util.Assert;
 12
 13 import com.ldd600.exception.base.BaseAppRuntimeException;
import com.ldd600.exception.base.BaseAppRuntimeException;
 14 import com.ldd600.exception.base.ConfigException;
import com.ldd600.exception.base.ConfigException;
 15 import com.ldd600.exception.base.handler.ExceptionHandler;
import com.ldd600.exception.base.handler.ExceptionHandler;
 16 import com.ldd600.exception.config.ExceptionDefinition;
import com.ldd600.exception.config.ExceptionDefinition;
 17
 18
 public class ExceptionContext
public class ExceptionContext  {
{
 19 private Map<Class<?>, ExceptionDefinition> exceptionMap;
    private Map<Class<?>, ExceptionDefinition> exceptionMap;
 20
 21 private Map<String, ExceptionHandler> handlers = new HashMap<String, ExceptionHandler>();
    private Map<String, ExceptionHandler> handlers = new HashMap<String, ExceptionHandler>();
 22
 23
 ExceptionContext()
    ExceptionContext()  {
{
 24 exceptionMap = new HashMap<Class<?>, ExceptionDefinition>();
        exceptionMap = new HashMap<Class<?>, ExceptionDefinition>();
 25 }
    }
 26
 27
 public boolean containsException(Class<?> expClazz)
    public boolean containsException(Class<?> expClazz)  {
{
 28 return (exceptionMap.containsKey(expClazz));
        return (exceptionMap.containsKey(expClazz));
 29 }
    }
 30 
    
 31
 public void addExceptionHander(Class<?> expClazz, Class<? extends ExceptionHandler> handlerClazz)
    public void addExceptionHander(Class<?> expClazz, Class<? extends ExceptionHandler> handlerClazz)  {
{
 32
 try
        try  {
{
 33 ExceptionDefinition definition = getRealExceptionDefinition(expClazz);
            ExceptionDefinition definition = getRealExceptionDefinition(expClazz);
 34
 if (null == definition)
            if (null == definition)  {
{
 35 throw new IllegalArgumentException(expClazz.getName() + "not in the context, please configure or add it to the context first!!");
                throw new IllegalArgumentException(expClazz.getName() + "not in the context, please configure or add it to the context first!!");
 36 }
            } 
 37 ExceptionHandler handler = handlers.get(handlerClazz.getName());
            ExceptionHandler handler = handlers.get(handlerClazz.getName());
 38
 if (null == handler)
            if (null == handler)  {
{
 39 handler = handlerClazz.newInstance();
                handler = handlerClazz.newInstance();
 40 handlers.put(handlerClazz.getName(), handler);
                handlers.put(handlerClazz.getName(), handler);
 41 }
            }
 42 
            
 43 definition.getHandlerNames().add(handlerClazz.getName());
            definition.getHandlerNames().add(handlerClazz.getName());
 44
 } catch (Exception ex)
        } catch (Exception ex)  {
{
 45 throw new ConfigException("Add exception handler to context failure!", ex);
            throw new ConfigException("Add exception handler to context failure!", ex);
 46 }
        }
 47 }
    }
 48 
    
 49
 public void addExceptionHandler(Class<?> expClazz, String errorCode, Class<? extends ExceptionHandler> handlerClazz)
    public void addExceptionHandler(Class<?> expClazz, String errorCode, Class<? extends ExceptionHandler> handlerClazz)  {
{
 50 Assert.hasLength(errorCode, expClazz + " errorCode must not be null or empty string!");
        Assert.hasLength(errorCode, expClazz + " errorCode must not be null or empty string!");
 51 ExceptionDefinition definition = getRealExceptionDefinition(expClazz);
        ExceptionDefinition definition = getRealExceptionDefinition(expClazz);
 52
 if(null == definition)
        if(null == definition)  {
{
 53 definition = new ExceptionDefinition(errorCode);
            definition = new ExceptionDefinition(errorCode);
 54 exceptionMap.put(expClazz, definition);
            exceptionMap.put(expClazz, definition);
 55 }
        }
 56 addExceptionHander(expClazz, handlerClazz);
        addExceptionHander(expClazz, handlerClazz);
 57 }
    }
 58 
    
 59 
    
 60 
    
 61
 public void addExceptionHandlers(Class<?> expClazz, Class<? extends ExceptionHandler>
    public void addExceptionHandlers(Class<?> expClazz, Class<? extends ExceptionHandler> handlerClazzes)
 handlerClazzes)  {
{
 62
 for(Class<? extends ExceptionHandler> handlerClazz : handlerClazzes)
        for(Class<? extends ExceptionHandler> handlerClazz : handlerClazzes)  {
{
 63 addExceptionHander(expClazz, handlerClazz);
            addExceptionHander(expClazz, handlerClazz);
 64 }
        }
 65 }
    }
 66
 67
 public void removeExceptionHandler(Class<?> expClazz, Class<? extends ExceptionHandler> handlerClazz)
    public void removeExceptionHandler(Class<?> expClazz, Class<? extends ExceptionHandler> handlerClazz)  {
{
 68 Assert.isTrue(containsException(expClazz));
        Assert.isTrue(containsException(expClazz));
 69 String handlerName = handlerClazz.getName();
        String handlerName = handlerClazz.getName();
 70 getExceptionDefinition(expClazz).getHandlerNames().remove(handlerName);
        getExceptionDefinition(expClazz).getHandlerNames().remove(handlerName);
 71 Collection<ExceptionDefinition> definitons = exceptionMap.values();
        Collection<ExceptionDefinition> definitons = exceptionMap.values();
 72 boolean isClearHandler = true;
        boolean isClearHandler = true;
 73
 for (ExceptionDefinition expDefinition : definitons)
        for (ExceptionDefinition expDefinition : definitons)  {
{
 74
 if (expDefinition.getHandlerNames().contains(handlerName))
            if (expDefinition.getHandlerNames().contains(handlerName))  {
{
 75 isClearHandler = false;
                isClearHandler = false;
 76 break;
                break;
 77 }
            }
 78 }
        }
 79
 80
 if (isClearHandler)
        if (isClearHandler)  {
{
 81 handlers.remove(handlers.get(handlerName));
            handlers.remove(handlers.get(handlerName));
 82 }
        }
 83 }
    }
 84
 85
 public void setExceptionDefinition(Class<?> expClazz, ExceptionDefinition definition)
    public void setExceptionDefinition(Class<?> expClazz, ExceptionDefinition definition)  {
{
 86 exceptionMap.put(expClazz, definition);
        exceptionMap.put(expClazz, definition);
 87 }
    }
 88
 89
 public ExceptionDefinition getExceptionDefinition(Class<?> expClazz)
    public ExceptionDefinition getExceptionDefinition(Class<?> expClazz)  {
{
 90
 if (containsException(expClazz))
        if (containsException(expClazz))  {
{
 91 return exceptionMap.get(expClazz);
            return exceptionMap.get(expClazz);  
 92
 } else if (BaseAppRuntimeException.class.isAssignableFrom(expClazz.getSuperclass()))
        } else if (BaseAppRuntimeException.class.isAssignableFrom(expClazz.getSuperclass()))  {
{
 93 return getExceptionDefinition(expClazz.getSuperclass());
            return getExceptionDefinition(expClazz.getSuperclass());
 94
 } else
        } else  {
{
 95 return null;
            return null;
 96 }
        }
 97 }
    }
 98 
    
 99
 public ExceptionDefinition getRealExceptionDefinition(Class<?> expClazz)
    public ExceptionDefinition getRealExceptionDefinition(Class<?> expClazz)  {
{
100 return exceptionMap.get(expClazz);
        return exceptionMap.get(expClazz);
101 }
    }
102
103
 public List<ExceptionHandler> getExceptionHandlers(Class<?> expClazz)
    public List<ExceptionHandler> getExceptionHandlers(Class<?> expClazz) {
{
104 ExceptionDefinition definition = getExceptionDefinition(expClazz);
        ExceptionDefinition definition = getExceptionDefinition(expClazz);
105
 if (null != definition)
        if (null != definition)  {
{
106 Set<String> handlerNames = definition.getHandlerNames();
            Set<String> handlerNames = definition.getHandlerNames();
107 List<ExceptionHandler> handlerList = new ArrayList<ExceptionHandler>(handlerNames.size());
            List<ExceptionHandler> handlerList = new ArrayList<ExceptionHandler>(handlerNames.size());
108
 for (String handlerName : handlerNames)
            for (String handlerName : handlerNames)  {
{
109 ExceptionHandler handler = handlers.get(handlerName);
                ExceptionHandler handler = handlers.get(handlerName);
110 handlerList.add(handler);
                handlerList.add(handler);
111 }
            }
112 List<ExceptionHandler> resultHandlerList = new ArrayList<ExceptionHandler>(handlerList);
            List<ExceptionHandler> resultHandlerList = new ArrayList<ExceptionHandler>(handlerList);
113 return resultHandlerList;
            return resultHandlerList;
114
 } else
        } else  {
{
115 return Collections.<ExceptionHandler> emptyList();
            return Collections.<ExceptionHandler> emptyList();
116 }
        }
117 }
    }
118 
    
119
 public String getErrorCode(Class<?> expClazz)
    public String getErrorCode(Class<?> expClazz) {
{
120 ExceptionDefinition definition = getExceptionDefinition(expClazz);
        ExceptionDefinition definition = getExceptionDefinition(expClazz);
121
 if (null != definition)
        if (null != definition)  {
{
122 return definition.getErrorCode();
            return definition.getErrorCode();
123
 } else
        } else  {
{
124 return "";
            return "";
125 }
        }
126 }
    }
127 
    
128 
    
129 }
}
130
 
 
ExceptionDefinition: Exception信息单元
 
 1 package com.ldd600.exception.config;
package com.ldd600.exception.config;
 2
 3 import java.util.LinkedHashSet;
import java.util.LinkedHashSet;
 4 import java.util.Set;
import java.util.Set;
 5
 6
 public class ExceptionDefinition
public class ExceptionDefinition  {
{
 7 private String errorCode;
    private String errorCode;
 8
 9 private Set<String> handlerNames = new LinkedHashSet<String> ();
    private Set<String> handlerNames = new LinkedHashSet<String> ();
10
11
 ExceptionDefinition()
    ExceptionDefinition()  {
{
12 
        
13 }
    }
14 
    
15
 public ExceptionDefinition(String errorCode)
    public ExceptionDefinition(String errorCode)  {
{
16 this.errorCode = errorCode;
        this.errorCode = errorCode;
17 }
    }
18 
    
19
 public String getErrorCode()
    public String getErrorCode()  {
{
20 return errorCode;
        return errorCode;
21 }
    }
22
23
 public void setErrorCode(String errorCode)
    public void setErrorCode(String errorCode)  {
{
24 this.errorCode = errorCode;
        this.errorCode = errorCode;
25 }
    }
26
27
 public Set<String> getHandlerNames()
    public Set<String> getHandlerNames()  {
{
28 return handlerNames;
        return handlerNames;
29 }
    }
30 }
}
31
 
 
ExceptionDefiniton定义了和某个exception相关的具体信息,根据exception的class name可以从exceptionContext中的exceptionMap得到指定的exception的相关信息,这些信息是在系统初始化时读取到exceptionContext中的。并且避免了exception handler的重复初始化。
 
可配置,受管式,方便使用
 采取两种配置方式,exception的相关信息比如它的errorCode, exceptionHandlers可以配置在外部的xml文件中,也可以用annotation标注。对于exception的处理是有继承性质的,如果某个exception没有在exceptionContext中注册,就使用它的父类的配置信息。如果无任何父类在exceptionContext中注册,就使用默认机制进行处理。
 
XML 方案:
            因为spring2.0支持自定义schema功能,我们可以方便地采用自己的schema只要实现NamespaceHandler和BeanDefinitionPaser,后面一个比较重要,可以将自定义xml文件中的相关类注册到spring的上下文中,成为spring bean。
Xml schema: 
 <xsd:complexType name="exceptionType">
<xsd:complexType name="exceptionType">
 <xsd:sequence>
        <xsd:sequence>
 <xsd:element name="level" default="error" minOccurs="0">
            <xsd:element name="level" default="error" minOccurs="0">
 <xsd:simpleType>
                <xsd:simpleType>
 <xsd:restriction base="xsd:string">
                    <xsd:restriction base="xsd:string">
 <xsd:enumeration value="error" />
                        <xsd:enumeration value="error" />
 <xsd:enumeration value="warning" />
                        <xsd:enumeration value="warning" />
 <xsd:enumeration value="info" />
                        <xsd:enumeration value="info" />
 <xsd:enumeration value="confirmation" />
                        <xsd:enumeration value="confirmation" />
 </xsd:restriction>
                    </xsd:restriction>
 </xsd:simpleType>
                </xsd:simpleType>
 </xsd:element>
            </xsd:element>
 <xsd:element name="handler" maxOccurs="unbounded">
            <xsd:element name="handler" maxOccurs="unbounded">
 <xsd:simpleType>
                <xsd:simpleType>
 <xsd:restriction base="xsd:string" />
                    <xsd:restriction base="xsd:string" />
 </xsd:simpleType>
                </xsd:simpleType>
 </xsd:element>
            </xsd:element>
 </xsd:sequence>
        </xsd:sequence>
 <xsd:attribute name="errorCode">
        <xsd:attribute name="errorCode">
 <xsd:simpleType>
            <xsd:simpleType>
 <xsd:restriction base="xsd:string">
                <xsd:restriction base="xsd:string">
 <xsd:whiteSpace value="preserve" />
                    <xsd:whiteSpace value="preserve" />
 <xsd:pattern value="LDD600-+\d{1,5}.*" />
                    <xsd:pattern value="LDD600-+\d{1,5}.*" />
 </xsd:restriction>
                </xsd:restriction>
 </xsd:simpleType>
            </xsd:simpleType>
 </xsd:attribute>
        </xsd:attribute>
 <xsd:attribute name="class" type="xsd:string" use="required" />
        <xsd:attribute name="class" type="xsd:string" use="required" />
 </xsd:complexType>
    </xsd:complexType>

Annotation方案:
            JDK1.5以上就有了annotation,可以简化我们的配置,使得配置信息和代码联系在一起,增加了代码的可读性。如何在spring中注册自定义的annotation和用annotation标注的class,可以参考文章2和文章:   。对于每个注册了的class用ExceptionalAnnotationBeanPostProcessor来parse具体的annotation信息(对于annotation的parse方法还会在以后继续改进)。
 1 package com.ldd600.exception.annotation;
package com.ldd600.exception.annotation;
 2
 3 import java.lang.annotation.Documented;
import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
import java.lang.annotation.Target;
 8
 9 import com.ldd600.exception.base.handler.ExceptionHandler;
import com.ldd600.exception.base.handler.ExceptionHandler;
10
11
 @Target(
@Target( {ElementType.TYPE})
{ElementType.TYPE})
12 @Retention(RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.RUNTIME)
13 @Documented
@Documented
14
 public @interface Exceptional
public @interface Exceptional  {
{
15 String errorCode();
    String errorCode();
16 Class<? extends ExceptionHandler>[] handlers();
    Class<? extends ExceptionHandler>[] handlers();
17 }
}
18
 
 1 package com.ldd600.exception.processor;
package com.ldd600.exception.processor;
 2
 3 import org.springframework.beans.BeansException;
import org.springframework.beans.BeansException;
 4 import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
 5
 6 import com.ldd600.exception.annotation.Exceptional;
import com.ldd600.exception.annotation.Exceptional;
 7 import com.ldd600.exception.base.BaseAppException;
import com.ldd600.exception.base.BaseAppException;
 8 import com.ldd600.exception.base.BaseAppRuntimeException;
import com.ldd600.exception.base.BaseAppRuntimeException;
 9 import com.ldd600.exception.config.ExceptionDefinition;
import com.ldd600.exception.config.ExceptionDefinition;
10 import com.ldd600.exception.context.ExceptionContext;
import com.ldd600.exception.context.ExceptionContext;
11 import com.ldd600.exception.context.CoreContextFactory;
import com.ldd600.exception.context.CoreContextFactory;
12
13
 public class ExceptionalAnnotationBeanPostProcessor implements BeanPostProcessor
public class ExceptionalAnnotationBeanPostProcessor implements BeanPostProcessor  {
{
14
15
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException  {
{
16
 if(bean instanceof BaseAppRuntimeException || bean instanceof BaseAppException)
       if(bean instanceof BaseAppRuntimeException || bean instanceof BaseAppException)  {
{
17 Exceptional exceptional = bean.getClass().getAnnotation(Exceptional.class);
           Exceptional exceptional = bean.getClass().getAnnotation(Exceptional.class);
18
 if(null != exceptional)
           if(null != exceptional)  {
{
19 ExceptionContext ctx = CoreContextFactory.getInstance().getExceptionContext();
               ExceptionContext ctx = CoreContextFactory.getInstance().getExceptionContext();
20
 if(!ctx.containsException(bean.getClass()))
               if(!ctx.containsException(bean.getClass()))  {
{
21 ExceptionDefinition expDefinition = new ExceptionDefinition(exceptional.errorCode());
                   ExceptionDefinition expDefinition = new ExceptionDefinition(exceptional.errorCode());
22 ctx.setExceptionDefinition(bean.getClass(), expDefinition);
                   ctx.setExceptionDefinition(bean.getClass(), expDefinition);
23 }
               }
24 ctx.addExceptionHandlers(bean.getClass(), exceptional.handlers());
               ctx.addExceptionHandlers(bean.getClass(), exceptional.handlers());
25 return null;
               return null;
26 }
           }
27 }
       }
28 return bean;
       return bean;
29 }
    }
30
31
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException  {
{
32 return bean;
            return bean;
33 }
    }
34
35 }
}
36
 
 
结果测试:
  1 package com.ldd600.exception.test;
package com.ldd600.exception.test;
  2
  3 import org.jmock.Expectations;
import org.jmock.Expectations;
  4 import org.jmock.Mockery;
import org.jmock.Mockery;
  5 import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactory;
  6
  7 import com.ldd600.exception.action.BusinessAction;
import com.ldd600.exception.action.BusinessAction;
  8 import com.ldd600.exception.base.BaseAppException;
import com.ldd600.exception.base.BaseAppException;
  9 import com.ldd600.exception.base.BaseAppRuntimeException;
import com.ldd600.exception.base.BaseAppRuntimeException;
 10 import com.ldd600.exception.base.ConfigException;
import com.ldd600.exception.base.ConfigException;
 11 import com.ldd600.exception.base.handler.ConsoleHandler;
import com.ldd600.exception.base.handler.ConsoleHandler;
 12 import com.ldd600.exception.context.CoreContextFactory;
import com.ldd600.exception.context.CoreContextFactory;
 13 import com.ldd600.exception.dto.DefaultRequest;
import com.ldd600.exception.dto.DefaultRequest;
 14 import com.ldd600.exception.dto.DefaultResponse;
import com.ldd600.exception.dto.DefaultResponse;
 15 import com.ldd600.exception.dto.Request;
import com.ldd600.exception.dto.Request;
 16 import com.ldd600.exception.dto.Response;
import com.ldd600.exception.dto.Response;
 17 import com.ldd600.exception.webservice.ActionBrokerImpl;
import com.ldd600.exception.webservice.ActionBrokerImpl;
 18
 19
 public class ExceptionTest extends DependencyInjectionExceptionTestCase
public class ExceptionTest extends DependencyInjectionExceptionTestCase  {
{
 20 Mockery context = new Mockery();
    Mockery context = new Mockery();
 21 ActionBrokerImpl broker = new ActionBrokerImpl();
    ActionBrokerImpl broker = new ActionBrokerImpl();
 22 final Request request = new DefaultRequest();
    final Request request = new DefaultRequest();
 23 final Response response = new DefaultResponse();
    final Response response = new DefaultResponse();
 24
 25 @Override
    @Override
 26
 protected String[] getConfigLocations()
    protected String[] getConfigLocations()  {
{
 27
 return new String[]
        return new String[]  { "applicationContext.xml" };
{ "applicationContext.xml" };
 28 }
    }
 29
 30
 public void testExceptionThrow()
    public void testExceptionThrow()  {
{
 31 final BusinessAction<Response, Request> action = context
        final BusinessAction<Response, Request> action = context
 32 .mock(BusinessAction.class);
                .mock(BusinessAction.class);
 33 final BeanFactory beanFactory = context.mock(BeanFactory.class);
        final BeanFactory beanFactory = context.mock(BeanFactory.class);
 34
 assertThrowing(new Closure()
        assertThrowing(new Closure()  {
{
 35
 public void run() throws Throwable
            public void run() throws Throwable  {
{
 36
 context.checking(new Expectations()
                context.checking(new Expectations()  {
{
 37
 
                     {
{
 38 allowing(beanFactory).getBean("action");
                        allowing(beanFactory).getBean("action");
 39 will(returnValue(action));
                        will(returnValue(action));
 40 one(action).execute(request, response);
                        one(action).execute(request, response);
 41 will(throwException(new BaseAppException()));
                        will(throwException(new BaseAppException()));
 42 }
                    }
 43 });
                });
 44 broker.setExceptionHandler(new ConsoleHandler());
                broker.setExceptionHandler(new ConsoleHandler());
 45 broker.setBeanFactory(beanFactory);
                broker.setBeanFactory(beanFactory);
 46 broker.execute("action", request, response);
                broker.execute("action", request, response);
 47 }
            }
 48
 49 }, BaseAppException.class);
        }, BaseAppException.class);
 50 }
    }
 51
 52
 public void testExceptionalAutoLoad() throws BaseAppException
    public void testExceptionalAutoLoad() throws BaseAppException  {
{
 53 final BeanFactory beanFactory = context.mock(BeanFactory.class);
        final BeanFactory beanFactory = context.mock(BeanFactory.class);
 54 final BusinessAction<Response, Request> action = context
        final BusinessAction<Response, Request> action = context
 55 .mock(BusinessAction.class);
                .mock(BusinessAction.class);
 56
 context.checking(new Expectations()
        context.checking(new Expectations()  {
{
 57
 
             {
{
 58 allowing(beanFactory).getBean("action");
                allowing(beanFactory).getBean("action");
 59 will(returnValue(action));
                will(returnValue(action));
 60 one(action).execute(request, response);
                one(action).execute(request, response);
 61 will(throwException(new ConfigException()));
                will(throwException(new ConfigException()));
 62 }
            }
 63 });
        });
 64 broker.setBeanFactory(beanFactory);
        broker.setBeanFactory(beanFactory);
 65 broker.execute("action", request, response);
        broker.execute("action", request, response);
 66 assertEquals(CoreContextFactory.getInstance().getExceptionContext()
        assertEquals(CoreContextFactory.getInstance().getExceptionContext()
 67 .getErrorCode(ConfigException.class), "LDD600-00002");
                .getErrorCode(ConfigException.class), "LDD600-00002");
 68 context.assertIsSatisfied();
        context.assertIsSatisfied();
 69 }
    }
 70
 71
 public void testRuntimeException()
    public void testRuntimeException()  {
{
 72 final BusinessAction<Response, Request> action = context
        final BusinessAction<Response, Request> action = context
 73 .mock(BusinessAction.class);
                .mock(BusinessAction.class);
 74 final BeanFactory beanFactory = context.mock(BeanFactory.class);
        final BeanFactory beanFactory = context.mock(BeanFactory.class);
 75
 assertThrowing(new Closure()
        assertThrowing(new Closure()  {
{
 76
 public void run() throws Throwable
            public void run() throws Throwable  {
{
 77
 context.checking(new Expectations()
                context.checking(new Expectations()  {
{
 78
 
                     {
{
 79 allowing(beanFactory).getBean("action");
                        allowing(beanFactory).getBean("action");
 80 will(returnValue(action));
                        will(returnValue(action));
 81 one(action).execute(request, response);
                        one(action).execute(request, response);
 82 will(throwException(new BaseAppRuntimeException()));
                        will(throwException(new BaseAppRuntimeException()));
 83 }
                    }
 84 });
                });
 85 broker.setExceptionHandler(new ConsoleHandler());
                broker.setExceptionHandler(new ConsoleHandler());
 86 broker.setBeanFactory(beanFactory);
                broker.setBeanFactory(beanFactory);
 87 broker.execute("action", request, response);
                broker.execute("action", request, response);
 88 }
            }
 89
 90 }, BaseAppRuntimeException.class);
        }, BaseAppRuntimeException.class);
 91 // test config
        // test config
 92 assertEquals(CoreContextFactory.getInstance().getExceptionContext()
        assertEquals(CoreContextFactory.getInstance().getExceptionContext()
 93 .getErrorCode(BaseAppRuntimeException.class), "LDD600-00001");
                .getErrorCode(BaseAppRuntimeException.class), "LDD600-00001");
 94 // test handler
        // test handler
 95 assertFalse(response.isSuccess());
        assertFalse(response.isSuccess());
 96 assertEquals(response.getErrorCode(), CoreContextFactory.getInstance()
        assertEquals(response.getErrorCode(), CoreContextFactory.getInstance()
 97 .getExceptionContext().getErrorCode(
                .getExceptionContext().getErrorCode(
 98 BaseAppRuntimeException.class));
                        BaseAppRuntimeException.class));
 99 context.assertIsSatisfied();
        context.assertIsSatisfied();
100 }
    }
101
102
 public void testCheckedException()
    public void testCheckedException()  {
{
103 final BusinessAction<Response, Request> action = context
        final BusinessAction<Response, Request> action = context
104 .mock(BusinessAction.class);
                .mock(BusinessAction.class);
105 final BeanFactory beanFactory = context.mock(BeanFactory.class);
        final BeanFactory beanFactory = context.mock(BeanFactory.class);
106
 assertThrowing(new Closure()
        assertThrowing(new Closure()  {
{
107
 public void run() throws Throwable
            public void run() throws Throwable  {
{
108
 context.checking(new Expectations()
                context.checking(new Expectations()  {
{
109
 
                     {
{
110 allowing(beanFactory).getBean("action");
                        allowing(beanFactory).getBean("action");
111 will(returnValue(action));
                        will(returnValue(action));
112 one(action).execute(request, response);
                        one(action).execute(request, response);
113 will(throwException(new ExceptionFaker()));
                        will(throwException(new ExceptionFaker()));
114 }
                    }
115 });
                });
116 broker.setBeanFactory(beanFactory);
                broker.setBeanFactory(beanFactory);
117 broker.execute("action", request, response);
                broker.execute("action", request, response);
118 }
            }
119
120 }, ExceptionFaker.class);
        }, ExceptionFaker.class);
121 // test config
        // test config
122 assertEquals(CoreContextFactory.getInstance().getExceptionContext()
        assertEquals(CoreContextFactory.getInstance().getExceptionContext()
123 .getErrorCode(ExceptionFaker.class), "LDD600-00003");
                .getErrorCode(ExceptionFaker.class), "LDD600-00003");
124 // test handler
        // test handler
125 assertFalse(response.isSuccess());
        assertFalse(response.isSuccess());
126 assertEquals(response.getErrorCode(), CoreContextFactory.getInstance()
        assertEquals(response.getErrorCode(), CoreContextFactory.getInstance()
127 .getExceptionContext().getErrorCode(
                .getExceptionContext().getErrorCode(
128 ExceptionFaker.class));
                        ExceptionFaker.class));
129 context.assertIsSatisfied();
        context.assertIsSatisfied();
130 }
    }
131 }
}
132
 
参考资料:
 
文章1:http://www.onjava.com/pub/a/onjava/2006/01/11/exception-handling-framework-for-j2ee.html
文章2:http://sannotations.sourceforge.net/
本文源代码:源代码下载