对于Exception的处理,究竟是采用check exception还是unchecked exception,众说纷纭,业绩很多大牛都有不同的意见,本文的关注点不在这个话题上,而是着重于,当我们程序中,需要把各种check exception转化为自定义的和业务逻辑相关的Runtime exceptionn的时候,如何利用Spring AOP来简化这一转化过程。
在实际工作中,如果我们也想像Spring Jdbctemplate一样,把check exception转化为Runtime exception的话,笨一点的办法就是在每次抛出check exception的地方都将其捕获,然后重新包装成Runtime exception,不过这样的话,不但重复工作量大,而且还容易产生遗漏,可谓事倍功半。那还要其它的什么办法能做到这一点呢?仔细分析下我们的我们面临的问题:即要在每个抛出check exception的方法里把异常包装成runtime exception重新抛出。这里有两个关键词很重要:每个。。。方法。。。,我们要在每个XX方法执行的时候都给其添加一项新的功能,这不正是AOP的用武之地。
因为Spring 提供了强大的AOP功能,我们就不需要自己去重复造轮子实现类似的功能,我翻了下Spring AOP部分的API,很快就找到ThrowsAdviceInterceptor这个类,这个类正好提供了我所需要的功能:
public ThrowsAdviceInterceptor(Object throwsAdvice) {
Assert.notNull(throwsAdvice, "Advice must not be null");
this.throwsAdvice = throwsAdvice;
Method[] methods = throwsAdvice.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (method.getName().equals(AFTER_THROWING) &&
//m.getReturnType() == null &&
(method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) &&
Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1])
) {
// Have an exception handler
this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method);
if (logger.isDebugEnabled()) {
logger.debug("Found exception handler method: " + method);
}
}
}
if (this.exceptionHandlerMap.isEmpty()) {
throw new IllegalArgumentException(
"At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
}
}
public int getHandlerMethodCount() {
return this.exceptionHandlerMap.size();
}
/**
* Determine the exception handle method. Can return null if not found.
* @param exception the exception thrown
* @return a handler for the given exception type
*/
private Method getExceptionHandler(Throwable exception) {
Class exceptionClass = exception.getClass();
if (logger.isTraceEnabled()) {
logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]");
}
Method handler = (Method) this.exceptionHandlerMap.get(exceptionClass);
while (handler == null && !exceptionClass.equals(Throwable.class)) {
exceptionClass = exceptionClass.getSuperclass();
handler = (Method) this.exceptionHandlerMap.get(exceptionClass);
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler);
}
return handler;
}
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
Method handlerMethod = getExceptionHandler(ex);
if (handlerMethod != null) {
invokeHandlerMethod(mi, ex, handlerMethod);
}
throw ex;
}
}
private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
Object[] handlerArgs;
if (method.getParameterTypes().length == 1) {
handlerArgs = new Object[] { ex };
}
else {
handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
}
try {
method.invoke(this.throwsAdvice, handlerArgs);
}
catch (InvocationTargetException targetEx) {
throw targetEx.getTargetException();
}
}
这个类的源代码并不复杂,简而言之就是根据注入的throwsAdvice,来生产针对各种不同的exception的AOP处理方法。其中有一点需要注意的是,在这个throwsAdvice当中,各种exception的处理方法都要以afterThrowing开头。见下面的例子:
public class CDMExceptionHandler implements ThrowsAdvice {
private static final int stackTraceLevel = 4;
public void afterThrowingFileNotFound(Method m, Object[] args, Object target,
FileNotFoundException ex) throws Exception {
//处理异常并包装成业务逻辑对应的Runtime exception,重新抛出
}
public void afterThrowing(Method m, Object[] args, Object target,
HttpHostConnectException ex) throws Exception {
//处理异常并包装成业务逻辑对应的Runtime exception,重新抛出
}
}
如果把ExceptionHandler 的实例当做throwsAdvice注入进ThrowsAdviceInterceptor的话,那么ThrowsAdviceInterceptor里的exceptionHandlerMap就有两个entery,分别为:
Key=FileNotFoundException, value(method)=afterThrowingFileNotFound
key=HttpHostConnectionException,value(method)=afterThrowingHttpHost。
在Invoke,ThrowsAdviceInterceptor根据捕获的异常从exceptionHandlerMethod里面get到相应的处理方法,进行处理。
通过对ThrowsAdviceInterceptor原理的简单分析,我们可以发现,其正好满足我们的需要,我们唯一要做的事情就是根据具体的应用,编写好自己的exceptionHandler即throwsAdvice,并将其注入进ThrowsAdviceInterceptor,然后把这个ThrowsAdviceInterceptor配置到我们的应用程序当中即可。至于AOP的具体配置,google下Spring AOP,将会有无数的文章教你如何配置,下面给出个简单的配置示例:
<bean id ="throwInterceptor" class="org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor">
<constructor-arg ref="throwAdvice" />
</bean>
<bean id ="throwAdvice" class="exceptionHandler.utils.ExceptionHandler">
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>contentPutServiceImpl</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>throwInterceptor</value>
</list>
</property>
</bean>
BeanNameAutoProxyCreator来配置需要在应用程序的那些类中使用ThrowsAdviceInterceptor。
分享到:
相关推荐
Maven坐标:org.springframework:spring-aop:5.0.10.RELEASE; 标签:spring、aop、springframework、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览...
Spring源码中最难的问题之一是循环依赖问题,当Spring AOP遇上循环依赖时,该如何解决? Spring通过三级缓存机制解决循环依赖的问题。 在Spring中,bean的实例化过程中,会先尝试从三级缓存中获取bean,这也是...
可扩展性强:使用 Spring AOP 进行方法耗时监测,可以方便的对其他的切面进行扩展,例如:日志、异常处理、权限控制等切面。 4. 提高系统性能:通过对系统中的方法进行耗时监测,可以及时发现系统中的性能瓶颈,...
我们在捕获到异常并对异常进行处理时可能会遇到如下一些问题: 1.不确定应如何处理这些异常 2.需要记录异常日志时没有记录,或者异常在不同的地方重复记录,使得排错调试不方便 3.处理日志时,需要在每一个try-catch...
12. **责任链模式(Chain of Responsibility)**:Spring AOP中的通知(Advice)链可以被视为责任链模式的应用,每个通知都可以选择处理请求或将其传递给下一个通知。 13. **观察者模式(Observer)**:Spring AOP...
Maven坐标:org.springframework:spring-aop:5.2.0.RELEASE; 标签:springframework、spring、aop、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 ...
Spring AOP,即面向切面编程,是Spring框架的核心组件之一,它允许程序员在不修改原有业务代码的情况下,对程序进行功能增强。本篇文章将详细阐述Spring AOP的基本概念、种类、代理原理、通知类型以及切入点,帮助你...
Maven坐标:org.springframework:spring-aop:5.0.8.RELEASE; 标签:springframework、spring、aop、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档...
Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这个"spring aop jar 包"包含了实现这一功能所需的类和接口,...
Maven坐标:org.springframework:spring-aop:5.3.15; 标签:spring、aop、springframework、jar包、java、中英对照文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 ...
Maven坐标:org.springframework:spring-aop:5.3.12; 标签:springframework、spring、aop、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 ...
spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...
### Spring AOP面向方面编程原理:AOP概念详解 #### 一、引言 随着软件系统的日益复杂,传统的面向对象编程(OOP)...对于希望深入了解Spring AOP原理与实践的读者来说,掌握以上概念将是开启面向方面编程之旅的第一步。
Spring AOP提供了两种实现方式:一是基于代理(Proxy-based AOP),二是基于字节码(Bytecode-based AOP)。基于代理的方式主要是使用Java动态代理或CGLIB生成代理对象;基于字节码的实现则依赖于ASM库,如AspectJ的...
Maven坐标:org.springframework:spring-aop:5.3.10; 标签:springframework、spring、aop、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化...
在 Spring AOP 中,`ObjenesisCglibAopProxy` 类负责使用 CGLIB 创建代理对象,它会将一系列的 `MethodInterceptor` 注册为 `Callback`,这些 `MethodInterceptor` 执行了 AOP 的逻辑。 在 Spring AOP 的自动代理...
- **XML配置**:在Spring的配置文件中,可以使用<aop:config>标签来定义切面,<aop:pointcut>定义切点,<aop:advisor>定义通知,<aop:aspect>将切点和通知关联起来。 - **注解配置**:Spring 2.5引入了基于注解的...
Maven坐标:org.springframework:spring-aop:5.2.15.RELEASE; 标签:springframework、spring、aop、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。...
Maven坐标:org.springframework:spring-aop:5.3.15; 标签:spring、aop、springframework、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...