樂在其中

          以JEE為主攻,以Flex為點綴,以Eclipse RCP為樂趣
          請訪問http://www.inframesh.org

          首頁 新隨筆 聯系 管理
            43 Posts :: 0 Stories :: 8 Comments :: 0 Trackbacks

          應用項目大致的體系結構:

              
           

           該異常處理框架滿足的要求:

          • 完整的異常組織結構
          • 異常的統一處理
          • 可配置,受管式,方便使用

           

          完整的異常組織結構:

          • 用戶可以方便的定義自己的異常,但所有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的工廠

           1package com.ldd600.exception.context;
           2
           3public class CoreContextFactory {
           4    private static CoreContextFactory instance;
           5
           6    private volatile ExceptionContext exceptionContext;
           7
           8    private Object exceptionContextLock = new Object();
           9
          10    private CoreContextFactory() {
          11
          12    }

          13
          14    public static synchronized CoreContextFactory getInstance() {
          15        if (null == instance) {
          16            instance = new CoreContextFactory();
          17        }

          18        return instance;
          19    }

          20
          21    public ExceptionContext getExceptionContext() {
          22        ExceptionContext tempExpContext = exceptionContext;
          23        if (tempExpContext == null
          24            synchronized (exceptionContextLock) {
          25                tempExpContext = exceptionContext;
          26                if (tempExpContext == null)
          27                    exceptionContext = tempExpContext = new ExceptionContext();
          28            }

          29        }

          30        return tempExpContext;
          31    }

          32}

          33



             

          ExceptionContext: 存放全局的exception信息

            1package com.ldd600.exception.context;
            2
            3import java.util.ArrayList;
            4import java.util.Collection;
            5import java.util.Collections;
            6import java.util.HashMap;
            7import java.util.List;
            8import java.util.Map;
            9import java.util.Set;
           10
           11import org.springframework.util.Assert;
           12
           13import com.ldd600.exception.base.BaseAppRuntimeException;
           14import com.ldd600.exception.base.ConfigException;
           15import com.ldd600.exception.base.handler.ExceptionHandler;
           16import com.ldd600.exception.config.ExceptionDefinition;
           17
           18public class ExceptionContext {
           19    private Map<Class<?>, ExceptionDefinition> exceptionMap;
           20
           21    private Map<String, ExceptionHandler> handlers = new HashMap<String, ExceptionHandler>();
           22
           23    ExceptionContext() {
           24        exceptionMap = new HashMap<Class<?>, ExceptionDefinition>();
           25    }

           26
           27    public boolean containsException(Class<?> expClazz) {
           28        return (exceptionMap.containsKey(expClazz));
           29    }

           30    
           31    public void addExceptionHander(Class<?> expClazz, Class<? extends ExceptionHandler> handlerClazz) {
           32        try {
           33            ExceptionDefinition definition = getRealExceptionDefinition(expClazz);
           34            if (null == definition) {
           35                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());
           38            if (null == handler) {
           39                handler = handlerClazz.newInstance();
           40                handlers.put(handlerClazz.getName(), handler);
           41            }

           42            
           43            definition.getHandlerNames().add(handlerClazz.getName());
           44        }
           catch (Exception ex) {
           45            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) {
           50        Assert.hasLength(errorCode, expClazz + " errorCode must not be null or empty string!");
           51        ExceptionDefinition definition = getRealExceptionDefinition(expClazz);
           52        if(null == definition) {
           53            definition = new ExceptionDefinition(errorCode);
           54            exceptionMap.put(expClazz, definition);
           55        }

           56        addExceptionHander(expClazz, handlerClazz);
           57    }

           58    
           59    
           60    
           61    public void addExceptionHandlers(Class<?> expClazz, Class<? extends ExceptionHandler> handlerClazzes) {
           62        for(Class<? extends ExceptionHandler> handlerClazz : handlerClazzes) {
           63            addExceptionHander(expClazz, handlerClazz);
           64        }

           65    }

           66
           67    public void removeExceptionHandler(Class<?> expClazz, Class<? extends ExceptionHandler> handlerClazz) {
           68        Assert.isTrue(containsException(expClazz));
           69        String handlerName = handlerClazz.getName();
           70        getExceptionDefinition(expClazz).getHandlerNames().remove(handlerName);
           71        Collection<ExceptionDefinition> definitons = exceptionMap.values();
           72        boolean isClearHandler = true;
           73        for (ExceptionDefinition expDefinition : definitons) {
           74            if (expDefinition.getHandlerNames().contains(handlerName)) {
           75                isClearHandler = false;
           76                break;
           77            }

           78        }

           79
           80        if (isClearHandler) {
           81            handlers.remove(handlers.get(handlerName));
           82        }

           83    }

           84
           85    public void setExceptionDefinition(Class<?> expClazz, ExceptionDefinition definition) {
           86        exceptionMap.put(expClazz, definition);
           87    }

           88
           89    public ExceptionDefinition getExceptionDefinition(Class<?> expClazz) {
           90        if (containsException(expClazz)) {
           91            return exceptionMap.get(expClazz);  
           92        }
           else if (BaseAppRuntimeException.class.isAssignableFrom(expClazz.getSuperclass())) {
           93            return getExceptionDefinition(expClazz.getSuperclass());
           94        }
           else {
           95            return null;
           96        }

           97    }

           98    
           99    public ExceptionDefinition getRealExceptionDefinition(Class<?> expClazz) {
          100        return exceptionMap.get(expClazz);
          101    }

          102
          103    public List<ExceptionHandler> getExceptionHandlers(Class<?> expClazz){
          104        ExceptionDefinition definition = getExceptionDefinition(expClazz);
          105        if (null != definition) {
          106            Set<String> handlerNames = definition.getHandlerNames();
          107            List<ExceptionHandler> handlerList = new ArrayList<ExceptionHandler>(handlerNames.size());
          108            for (String handlerName : handlerNames) {
          109                ExceptionHandler handler = handlers.get(handlerName);
          110                handlerList.add(handler);
          111            }

          112            List<ExceptionHandler> resultHandlerList = new ArrayList<ExceptionHandler>(handlerList);
          113            return resultHandlerList;
          114        }
           else {
          115            return Collections.<ExceptionHandler> emptyList();
          116        }

          117    }

          118    
          119    public String getErrorCode(Class<?> expClazz){
          120        ExceptionDefinition definition = getExceptionDefinition(expClazz);
          121        if (null != definition) {
          122            return definition.getErrorCode();
          123        }
           else {
          124            return "";
          125        }

          126    }

          127    
          128    
          129}

          130
           

          ExceptionDefinition: Exception信息單元

           1package com.ldd600.exception.config;
           2
           3import java.util.LinkedHashSet;
           4import java.util.Set;
           5
           6public class ExceptionDefinition {
           7    private String errorCode;
           8
           9    private Set<String> handlerNames = new LinkedHashSet<String> ();
          10
          11    ExceptionDefinition() {
          12        
          13    }

          14    
          15    public ExceptionDefinition(String errorCode) {
          16        this.errorCode = errorCode;
          17    }

          18    
          19    public String getErrorCode() {
          20        return errorCode;
          21    }

          22
          23    public void setErrorCode(String errorCode) {
          24        this.errorCode = errorCode;
          25    }

          26
          27    public Set<String> getHandlerNames() {
          28        return handlerNames;
          29    }

          30}

          31
           

          ExceptionDefiniton定義了和某個exception相關的具體信息,根據exceptionclass name可以從exceptionContext中的exceptionMap得到指定的exception的相關信息,這些信息是在系統初始化時讀取到exceptionContext中的。并且避免了exception handler的重復初始化。

           

          可配置,受管式,方便使用

           采取兩種配置方式,exception的相關信息比如它的errorCode exceptionHandlers可以配置在外部的xml文件中,也可以用annotation標注。對于exception的處理是有繼承性質的,如果某個exception沒有在exceptionContext中注冊,就使用它的父類的配置信息。如果無任何父類在exceptionContext中注冊,就使用默認機制進行處理。

          XML 方案:

                      因為spring2.0支持自定義schema功能,我們可以方便地采用自己的schema只要實現NamespaceHandlerBeanDefinitionPaser,后面一個比較重要,可以將自定義xml文件中的相關類注冊到spring的上下文中,成為spring bean

          Xml schema:

          <xsd:complexType name="exceptionType">
                  
          <xsd:sequence>
                      
          <xsd:element name="level" default="error" minOccurs="0">
                          
          <xsd:simpleType>
                              
          <xsd:restriction base="xsd:string">
                                  
          <xsd:enumeration value="error" />
                                  
          <xsd:enumeration value="warning" />
                                  
          <xsd:enumeration value="info" />
                                  
          <xsd:enumeration value="confirmation" />
                              
          </xsd:restriction>
                          
          </xsd:simpleType>
                      
          </xsd:element>
                      
          <xsd:element name="handler" maxOccurs="unbounded">
                          
          <xsd:simpleType>
                              
          <xsd:restriction base="xsd:string" />
                          
          </xsd:simpleType>
                      
          </xsd:element>
                  
          </xsd:sequence>
                  
          <xsd:attribute name="errorCode">
                      
          <xsd:simpleType>
                          
          <xsd:restriction base="xsd:string">
                              
          <xsd:whiteSpace value="preserve" />
                              
          <xsd:pattern value="LDD600-+"d{1,5}.*" />
                          
          </xsd:restriction>
                      
          </xsd:simpleType>
                  
          </xsd:attribute>
                  
          <xsd:attribute name="class" type="xsd:string" use="required" />
              
          </xsd:complexType>

           

          Annotation方案:

                      JDK1.5以上就有了annotation,可以簡化我們的配置,使得配置信息和代碼聯系在一起,增加了代碼的可讀性。如何在spring中注冊自定義的annotation和用annotation標注的class,可以參考文章2和文章:   。對于每個注冊了的classExceptionalAnnotationBeanPostProcessorparse具體的annotation信息(對于annotationparse方法還會在以后繼續改進)。

           1package com.ldd600.exception.annotation;
           2
           3import java.lang.annotation.Documented;
           4import java.lang.annotation.ElementType;
           5import java.lang.annotation.Retention;
           6import java.lang.annotation.RetentionPolicy;
           7import java.lang.annotation.Target;
           8
           9import com.ldd600.exception.base.handler.ExceptionHandler;
          10
          11@Target({ElementType.TYPE})
          12@Retention(RetentionPolicy.RUNTIME)
          13@Documented
          14public @interface Exceptional {
          15    String errorCode();
          16    Class<? extends ExceptionHandler>[] handlers();
          17}

          18


           1package com.ldd600.exception.processor;
           2
           3import org.springframework.beans.BeansException;
           4import org.springframework.beans.factory.config.BeanPostProcessor;
           5
           6import com.ldd600.exception.annotation.Exceptional;
           7import com.ldd600.exception.base.BaseAppException;
           8import com.ldd600.exception.base.BaseAppRuntimeException;
           9import com.ldd600.exception.config.ExceptionDefinition;
          10import com.ldd600.exception.context.ExceptionContext;
          11import com.ldd600.exception.context.CoreContextFactory;
          12
          13public class ExceptionalAnnotationBeanPostProcessor implements BeanPostProcessor {
          14
          15    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          16       if(bean instanceof BaseAppRuntimeException || bean instanceof BaseAppException) {
          17           Exceptional exceptional = bean.getClass().getAnnotation(Exceptional.class);
          18           if(null != exceptional) {
          19               ExceptionContext ctx = CoreContextFactory.getInstance().getExceptionContext();
          20               if(!ctx.containsException(bean.getClass())) {
          21                   ExceptionDefinition expDefinition = new ExceptionDefinition(exceptional.errorCode());
          22                   ctx.setExceptionDefinition(bean.getClass(), expDefinition);
          23               }

          24               ctx.addExceptionHandlers(bean.getClass(), exceptional.handlers());
          25               return null;
          26           }

          27       }

          28       return bean;
          29    }

          30
          31    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
          32            return bean;
          33    }

          34
          35}

          36
           

          結果測試:

            1package com.ldd600.exception.test;
            2
            3import org.jmock.Expectations;
            4import org.jmock.Mockery;
            5import org.springframework.beans.factory.BeanFactory;
            6
            7import com.ldd600.exception.action.BusinessAction;
            8import com.ldd600.exception.base.BaseAppException;
            9import com.ldd600.exception.base.BaseAppRuntimeException;
           10import com.ldd600.exception.base.ConfigException;
           11import com.ldd600.exception.base.handler.ConsoleHandler;
           12import com.ldd600.exception.context.CoreContextFactory;
           13import com.ldd600.exception.dto.DefaultRequest;
           14import com.ldd600.exception.dto.DefaultResponse;
           15import com.ldd600.exception.dto.Request;
           16import com.ldd600.exception.dto.Response;
           17import com.ldd600.exception.webservice.ActionBrokerImpl;
           18
           19public class ExceptionTest extends DependencyInjectionExceptionTestCase {
           20    Mockery context = new Mockery();
           21    ActionBrokerImpl broker = new ActionBrokerImpl();
           22    final Request request = new DefaultRequest();
           23    final Response response = new DefaultResponse();
           24
           25    @Override
           26    protected String[] getConfigLocations() {
           27        return new String[] "applicationContext.xml" };
           28    }

           29
           30    public void testExceptionThrow() {
           31        final BusinessAction<Response, Request> action = context
           32                .mock(BusinessAction.class);
           33        final BeanFactory beanFactory = context.mock(BeanFactory.class);
           34        assertThrowing(new Closure() {
           35            public void run() throws Throwable {
           36                context.checking(new Expectations() {
           37                    {
           38                        allowing(beanFactory).getBean("action");
           39                        will(returnValue(action));
           40                        one(action).execute(request, response);
           41                        will(throwException(new BaseAppException()));
           42                    }

           43                }
          );
           44                broker.setExceptionHandler(new ConsoleHandler());
           45                broker.setBeanFactory(beanFactory);
           46                broker.execute("action", request, response);
           47            }

           48
           49        }
          , BaseAppException.class);
           50    }

           51
           52    public void testExceptionalAutoLoad() throws BaseAppException {
           53        final BeanFactory beanFactory = context.mock(BeanFactory.class);
           54        final BusinessAction<Response, Request> action = context
           55                .mock(BusinessAction.class);
           56        context.checking(new Expectations() {
           57            {
           58                allowing(beanFactory).getBean("action");
           59                will(returnValue(action));
           60                one(action).execute(request, response);
           61                will(throwException(new ConfigException()));
           62            }

           63        }
          );
           64        broker.setBeanFactory(beanFactory);
           65        broker.execute("action", request, response);
           66        assertEquals(CoreContextFactory.getInstance().getExceptionContext()
           67                .getErrorCode(ConfigException.class), "LDD600-00002");
           68        context.assertIsSatisfied();
           69    }

           70
           71    public void testRuntimeException() {
           72        final BusinessAction<Response, Request> action = context
           73                .mock(BusinessAction.class);
           74        final BeanFactory beanFactory = context.mock(BeanFactory.class);
           75        assertThrowing(new Closure() {
           76            public void run() throws Throwable {
           77                context.checking(new Expectations() {
           78                    {
           79                        allowing(beanFactory).getBean("action");
           80                        will(returnValue(action));
           81                        one(action).execute(request, response);
           82                        will(throwException(new BaseAppRuntimeException()));
           83                    }

           84                }
          );
           85                broker.setExceptionHandler(new ConsoleHandler());
           86                broker.setBeanFactory(beanFactory);
           87                broker.execute("action", request, response);
           88            }

           89
           90        }
          , BaseAppRuntimeException.class);
           91        // test config
           92        assertEquals(CoreContextFactory.getInstance().getExceptionContext()
           93                .getErrorCode(BaseAppRuntimeException.class), "LDD600-00001");
           94        // test handler
           95        assertFalse(response.isSuccess());
           96        assertEquals(response.getErrorCode(), CoreContextFactory.getInstance()
           97                .getExceptionContext().getErrorCode(
           98                        BaseAppRuntimeException.class));
           99        context.assertIsSatisfied();
          100    }

          101
          102    public void testCheckedException() {
          103        final BusinessAction<Response, Request> action = context
          104                .mock(BusinessAction.class);
          105        final BeanFactory beanFactory = context.mock(BeanFactory.class);
          106        assertThrowing(new Closure() {
          107            public void run() throws Throwable {
          108                context.checking(new Expectations() {
          109                    {
          110                        allowing(beanFactory).getBean("action");
          111                        will(returnValue(action));
          112                        one(action).execute(request, response);
          113                        will(throwException(new ExceptionFaker()));
          114                    }

          115                }
          );
          116                broker.setBeanFactory(beanFactory);
          117                broker.execute("action", request, response);
          118            }

          119
          120        }
          , ExceptionFaker.class);
          121        // test config
          122        assertEquals(CoreContextFactory.getInstance().getExceptionContext()
          123                .getErrorCode(ExceptionFaker.class), "LDD600-00003");
          124        // test handler
          125        assertFalse(response.isSuccess());
          126        assertEquals(response.getErrorCode(), CoreContextFactory.getInstance()
          127                .getExceptionContext().getErrorCode(
          128                        ExceptionFaker.class));
          129        context.assertIsSatisfied();
          130    }

          131}

          132


          參考資料:
           

          文章1http://www.onjava.com/pub/a/onjava/2006/01/11/exception-handling-framework-for-j2ee.html

          文章2http://sannotations.sourceforge.net/

          本文源代碼:源代碼下載

          posted on 2009-02-12 22:58 suprasoft Inc,. 閱讀(300) 評論(0)  編輯  收藏 所屬分類: J2EE
          ©2005-2008 Suprasoft Inc., All right reserved.
          主站蜘蛛池模板: 铜山县| 新宁县| 家居| 杨浦区| 嘉禾县| 衢州市| 醴陵市| 青州市| 汪清县| 尼勒克县| 门源| 肇庆市| 临海市| 张家口市| 商丘市| 呼伦贝尔市| 开原市| 德阳市| 卢湾区| 茂名市| 高雄县| 平定县| 昌邑市| 梅州市| 和田市| 太白县| 政和县| 鄄城县| 恩施市| 牟定县| 象州县| 太白县| 铜梁县| 平阴县| 望江县| 中卫市| 上思县| 长子县| 潮州市| 金湖县| 金秀|