SpringAOP使用扩展
在《初识Spring》中我们了解到Spring支持AOP且可配置方法的前置曾强和后置曾强,但其实Spring支持多种曾强类型。下面同过一些例子来介绍Spring的几种常用的曾强(前置增强和后置曾强不再进行介绍,详情可参阅《初识Spring》这篇博客)。
异常抛出曾强
异常抛出曾强的特点是在目标方法抛出异常时织入曾强处理。首先我们要编写一个实现异常曾强代码的类,给类实现ThrowsAdvice接口。如下所示:
复制代码
packagecn.wz.aop;
importjava.lang.reflect.Method;
importorg.apache.log4j.Logger;
importorg.springframework.aop.ThrowsAdvice;
publicclassErrorLoggerimplementsThrowsAdvice{
Loggerlog=Logger.getLogger(ErrorLogger.class);
/
实现异常曾强代码的方法
@parammethod目标方法名
@paramargs向目标方法传入的参数
@paramtarget目标方法所在的类的实例
@parame目标方法内所抛出的异常对象
/
publicvoidafterThrowing(Methodmethod,Object[]args,Objecttarget,Exceptione){
log.error(method.getName()+"发生异常:"+e);
}
}
复制代码
上述代码通过实现ThrowsAdvice接口实现异常抛出曾强,其中ThrowsAdvice接口中没有定义任何方法,但我们在定义异常抛出的曾强方法时必须遵守以下方法签名:
voidafterThrowing([Methodmethod,Object[]arguments,Objecttarget,]Throwableex)
这里Spring规定了方法名必须是“afterThrowing”。方法参数只有最后一个是必须的,前面三个参数是可选的,但是前面三个参数只能是要么都提供,要么都不提供!否则则无法实现曾强。下面编写测试类进行测试:
复制代码
packagecn.wz.test;
importorg.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
publicclassExceptionTest{
publicstaticvoidmain(String[]args)throwsException{
ApplicationContextcontext=newClassPathXmlApplicationContext("applicationContext.xml");
ExceptionTestbean=context.getBean("test",ExceptionTest.class);
bean.add();
}
publicvoidadd()throwsException{
thrownewException("错误");
}
}
复制代码
最终运行结果:
image
对于Spring配置文件的配置方法与前置增强和后置曾强的配置方法相同这里不再进行演示,
环绕曾强
环绕曾强在目标方法的前后都可以织入曾强处理。环绕增强是功能最强大的增强处理,Spring把目标方法的控制权全部交给了它。在环绕曾强处理中,可以获取或修改目标方法的参数,返回值,可以对它进行异常处理,甚至可以决定目标方法是否执行!
好了下面来看看如何实现环绕曾强吧。首先还是要定义实现环绕曾强代码的类,该类实现了MethodInterceptor接口的invoke()方法,在invoke()方法中编写曾强代码。
复制代码
packagecn.wz.aop;
importjava.lang.reflect.Method;
importjava.util.Arrays;
importorg.aopalliance.intercept.MethodInterceptor;
importorg.aopalliance.intercept.MethodInvocation;
importorg.apache.www.tt951.comlog4j.Logger;
publicclassErrorLoggerimplementsMethodInterceptor{
Loggerlog=Logger.getLogger(ErrorLogger.class);
publicObjectinvoke(MethodInvocationarg0)throwsThrowable{
Methodmethod=arg0.getMethod();
Object[]arguments=arg0.getArguments();
Objecttarget=arg0.getThis();
log.info("调用"+target+"的"+method.getName()+"方法。方法入参:"+Arrays.toString(arguments));
try{
Objectresult=arg0.proceed();
log.info("调用"+target+"的"+method.getName()+"方法。方法返回值:"+result);
returnresult;
}catch(Exceptione){
log.error(method.getName()+"方法异常:"+e);
}
returnnull;
}
}
复制代码
上述代码通过MethodInterceptor接口实现了环绕增强。该接口要求实现invoke方法,其参数MethodInvocation不但疯转了目标方法及其入参数组,还封装了被代理的目标对象。通过proceed方法可以调用目标对象响应的方法,从而实现对目标方法的完全控制。借助异常抛出曾强的测试代码进行测试其运行结果如下:
image
使用注解实现曾强
除了实现Spring提供的特定接口外,Spring还可以通过集成AspectJ实现了以注解的方式定义增强类。大大减少了配置文件中的工作量。
注意:使用Aspectj是要确保JDK的版本是5.0或以上的版本,否则将无法使用注解技术,其次还要引入asm模块的jar包到项目中
前置曾强和后置曾强类:
复制代码
packagecn.wz.aop;
importorg.apache.log4j.Logger;
importorg.aspectj.lang.annotation.AfterReturning;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Before;
@Aspect
publicclassUserLogger{
privatestaticfinalLoggerlog=Logger.getLogger(UserLogger.class);
@Before("execution(publicvoidadd())")
publicvoidbefore(){
log.info("前置增强");
}
@AfterReturning("execution(publicvoidadd())")
publicvoidafterReturning(){
log.info("后置增强");
}
}
复制代码
在Spring配置文件中的配置如下:
image
异常抛出增强类:
复制代码
packagecn.wz.aop;
importorg.apache.log4j.Logger;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.annotation.AfterThrowing;
importorg.aspectj.lang.annotation.Aspect;
@Aspect
publicclassError_Logger{
privatestaticfinalLoggerlog=Logger.getLogger(UserLogger.class);
@AfterThrowing(pointcut="execution(publicvoidadd())",throwing="e")
publicvoidagterThrowing(JoinPointjp,Exceptione){
log.error(jp.getSignature().getName()+"发生异常:"+e);
}
}
复制代码
环绕增强类:
复制代码
packagecn.wz.aop;
importorg.apache.log4j.Logger;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
@Aspect
publicclassArounsLogger{
privatestaticfinalLoggerlog=Logger.getLogger(UserLogger.class);
@Around("executwww.baiyuewang.netion(publicvoidadd())")
publicObjectaroundLogger(ProceedingJoinPointjp)throwsThrowable{
System.out.println("前置增强");
Objectobj=jp.proceed();//调用原始方法
System.out.println("后置增强");
returnobj;
}
}
|
|