在Spring基本上实现本身的异常处理惩罚框架
当前位置:以往代写 > JAVA 教程 >在Spring基本上实现本身的异常处理惩罚框架
2019-06-14

在Spring基本上实现本身的异常处理惩罚框架

在Spring基本上实现本身的异常处理惩罚框架

副标题#e#在Spring根基上实现自己的异常处理惩罚处罚框架

该异常处理惩罚框架满意的要求:

完整的异常组织布局

异常的统一处理惩罚

可设置,受管式,利便利用

完整的异常组织布局:

用户可以利便的界说本身的异常,但所有UncheckedException需要担任BaseAppRuntimeException,所有的checked Exception可以担任BaseAppException,可能需要抛出且不需要check时用WrapperredAppException封装后抛出

公道地利用checked异常

Exception有独一的error code,这样用户陈诉异常后,可以按照异常号找到相应Exception,把exception直接显示给用户也没有太大的意义,如何记载exception那就是下文讲到的ExceptionHandler的职责了。

假如是第三方包罗jdk中的异常,需要封装成BaseAppException可能BaseAppRuntimeException后抛出

在Spring根基上实现自己的异常处理惩罚处罚框架


#p#副标题#e#

统一的异常处理惩罚

异常统一在框架中举办处理惩罚,不需要在上层应用的代码中去处理惩罚抛出的异常。为了只管捕获到所有的异常,将异常处理惩罚放在了ActionBroker中,这样每每action今后抛出的异常都可以捕获到,因为webservice只是简朴的挪用action类的要领,一般不会呈现异常。当我们捕获到异常后,需要举办异常处理惩罚,界说了ExceptionHandler接口,用接口抽象出异常处理惩罚类的详细实现。

在Spring根基上实现自己的异常处理惩罚处罚框架

USFContextFactory: 建设ExceptionContext的工场

package 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

#p#副标题#e#

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

#p#副标题#e#

ExceptionDefinition: Exception信息单位

#p#分页标题#e#

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

#p#分页标题#e#

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: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>

#p#副标题#e#

Annotation方案:

JDK1.5以上就有了annotation,可以简化我们的设置,使得设置信息和代码接洽在一起,增加了代码的可读性。如安在spring中注册自界说的annotation和用annotation标注的class,可以参考文章2和文章:  。对付每个注册了的class用ExceptionalAnnotationBeanPostProcessor来parse详细的annotation信息(对付annotation的parse要领还会在今后继承改造)。

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
[email protected]({ElementType.TYPE})
[email protected](RetentionPolicy.RUNTIME)
[email protected]
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

#p#副标题#e#

功效测试:

#p#分页标题#e#

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

    关键字:

在线提交作业