springmvc配置AOP的两种方式
本文内容纲要:
spingmvc配置AOP有两种方式,一种是利用注解的方式配置,另一种是XML配置实现。
应用注解的方式配置:
先在maven中引入AOP用到的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
<!--aopaspect注解导包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
然后在springmvc的配置文件中加入AOP的配置,即扫描AOP的包以及让AOP生效
<!--AOP注解方式;定义Aspect-->
<!--激活组件扫描功能,在包"com.example.aop及其子包下面自动扫描通过注解配置的组件-->
<context:component-scanbase-package="com.example.aop"/>
<!--启动AspectJ支持只对扫描过的bean有效-->
<aop:aspectj-autoproxyproxy-target-class="true"/>
然后加入AOP逻辑处理类
packagecom.example.aop;
importjava.util.Arrays;
importjava.util.List;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.After;
importorg.aspectj.lang.annotation.AfterReturning;
importorg.aspectj.lang.annotation.AfterThrowing;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Before;
importorg.aspectj.lang.annotation.Pointcut;
importorg.springframework.core.annotation.Order;
importorg.springframework.stereotype.Component;
@Aspect//该标签把LoggerAspect类声明为一个切面
@Order(1)//设置切面的优先级:如果有多个切面,可通过设置优先级控制切面的执行顺序(数值越小,优先级越高)
@Component//该标签把LoggerAspect类放到IOC容器中
publicclassLoggerAspect{
/**
*定义一个方法,用于声明切入点表达式,方法中一般不需要添加其他代码
*使用@Pointcut声明切入点表达式
*后面的通知直接使用方法名来引用当前的切点表达式;如果是其他类使用,加上包名即可
*/
@Pointcut("execution(public*com.example.controller.*Controller.*(..))")
publicvoiddeclearJoinPointExpression(){}
/**
*前置通知
*@paramjoinPoint
*/
@Before("declearJoinPointExpression()")//该标签声明次方法是一个前置通知:在目标方法开始之前执行
publicvoidbeforMethod(JoinPointjoinPoint){
StringmethodName=joinPoint.getSignature().getName();
List<Object>args=Arrays.asList(joinPoint.getArgs());
System.out.println("thismethod"+methodName+"begin.param<"+args+">");
}
/**
*后置通知(无论方法是否发生异常都会执行,所以访问不到方法的返回值)
*@paramjoinPoint
*/
@After("declearJoinPointExpression()")
publicvoidafterMethod(JoinPointjoinPoint){
StringmethodName=joinPoint.getSignature().getName();
System.out.println("thismethod"+methodName+"end.");
}
/**
*返回通知(在方法正常结束执行的代码)
*返回通知可以访问到方法的返回值!
*@paramjoinPoint
*/
@AfterReturning(value="declearJoinPointExpression()",returning="result")
publicvoidafterReturnMethod(JoinPointjoinPoint,Objectresult){
StringmethodName=joinPoint.getSignature().getName();
System.out.println("thismethod"+methodName+"end.result<"+result+">");
}
/**
*异常通知(方法发生异常执行的代码)
*可以访问到异常对象;且可以指定在出现特定异常时执行的代码
*@paramjoinPoint
*@paramex
*/
@AfterThrowing(value="declearJoinPointExpression()",throwing="ex")
publicvoidafterThrowingMethod(JoinPointjoinPoint,Exceptionex){
StringmethodName=joinPoint.getSignature().getName();
System.out.println("thismethod"+methodName+"end.exmessage<"+ex+">");
}
/**
*环绕通知(需要携带类型为ProceedingJoinPoint类型的参数)
*环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin类型的参数可以决定是否执行目标方法
*且环绕通知必须有返回值,返回值即目标方法的返回值
*@parampoint
*/
@Around(value="declearJoinPointExpression()")
publicObjectaroundMethod(ProceedingJoinPointpoint){
Objectresult=null;
StringmethodName=point.getSignature().getName();
try{
//前置通知
System.out.println("Themethod"+methodName+"start.param<"+Arrays.asList(point.getArgs())+">");
//执行目标方法
result=point.proceed();
//返回通知
System.out.println("Themethod"+methodName+"end.result<"+result+">");
}catch(Throwablee){
//异常通知
System.out.println("thismethod"+methodName+"end.exmessage<"+e+">");
thrownewRuntimeException(e);
}
//后置通知
System.out.println("Themethod"+methodName+"end.");
returnresult;
}
}
在类上加上注解Aspect声明这个类是一个切面,加上component注解加入IOC容器中。Order注解是优先级,如果只有一个切面类可以不用。注解pointcut是声明注解的作用范围。execution(public*com.example.controller.*Controller.*(..))我这里用的execution表达式,代表作用com.example.controller包下所有以Controller结尾类的所有Public方法。@pointcut所描述的方法里面通常不需要内容。切面通知包含:
前置通知(@Before,在执行方法之前,参数为JoinPoint)
后置通知(@After,无论方法抛不抛异常都会执行,所以获取不到方法的返回值。参数为JoinPoint)
返回通知(@AfterReturning,在方法正常结束后执行,可以获取到方法的返回值。参数为JoinPoint和result(Object))
异常通知(@AfterThrowing,在方法抛出异常时执行,可以获取到异常对象,且可以指定在出现特定异常时执行的代码,参数为JoinPoint何Exception)
环绕通知(@Around,环绕通知需要携带的类型为ProceedingJoinPoint类型的参数,环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin类型的参数可以决定是否执行目标方法,且环绕通知必须有返回值,返回值即目标方法的返回值)
应用XML方式配置
依赖的话,应该不用加入AOP注解的依赖。先定义一个类,作为切面类。
packagecom.example.aop;
importjava.util.Arrays;
importjava.util.List;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.springframework.stereotype.Component;
@Component//该标签把LoggerAspect类放到IOC容器中
publicclassSysAspect{
/**
*前置通知
*@paramjoinPoint
*/
publicvoidbeforMethod(JoinPointjoinPoint){
StringmethodName=joinPoint.getSignature().getName();
List<Object>args=Arrays.asList(joinPoint.getArgs());
System.out.println("thismethod"+methodName+"begin.param<"+args+">");
}
/**
*后置通知(无论方法是否发生异常都会执行,所以访问不到方法的返回值)
*@paramjoinPoint
*/
publicvoidafterMethod(JoinPointjoinPoint){
StringmethodName=joinPoint.getSignature().getName();
System.out.println("thismethod"+methodName+"end.");
}
/**
*返回通知(在方法正常结束执行的代码)
*返回通知可以访问到方法的返回值!
*@paramjoinPoint
*/
publicvoidafterReturnMethod(JoinPointjoinPoint,Objectresult){
StringmethodName=joinPoint.getSignature().getName();
System.out.println("thismethod"+methodName+"end.result<"+result+">");
}
/**
*异常通知(方法发生异常执行的代码)
*可以访问到异常对象;且可以指定在出现特定异常时执行的代码
*@paramjoinPoint
*@paramex
*/
publicvoidafterThrowingMethod(JoinPointjoinPoint,Exceptionex){
StringmethodName=joinPoint.getSignature().getName();
System.out.println("thismethod"+methodName+"end.exmessage<"+ex+">");
}
/**
*环绕通知(需要携带类型为ProceedingJoinPoint类型的参数)
*环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin类型的参数可以决定是否执行目标方法
*且环绕通知必须有返回值,返回值即目标方法的返回值
*@parampoint
*/
publicObjectaroundMethod(ProceedingJoinPointpoint){
Objectresult=null;
StringmethodName=point.getSignature().getName();
try{
//前置通知
System.out.println("Themethod"+methodName+"start.param<"+Arrays.asList(point.getArgs())+">");
//执行目标方法
result=point.proceed();
//返回通知
System.out.println("Themethod"+methodName+"end.result<"+result+">");
}catch(Throwablee){
//异常通知
System.out.println("thismethod"+methodName+"end.exmessage<"+e+">");
thrownewRuntimeException(e);
}
//后置通知
System.out.println("Themethod"+methodName+"end.");
returnresult;
}
}
可以看到,这个类除了没有@Aspect以及相关切面的注解外,跟正常的AOP切面类没有差别。如果声明其让其为一个切面。需要我们在xml文件中手动配置。
<!--配置切面的Bean-->
<beanid="sysAspect"class="com.example.aop.SysAspect"/>
<!--配置AOP-->
<aop:config>
<!--配置切点表达式-->
<aop:pointcutid="pointcut"expression="execution(public*com.example.controller.*Controller.*(..))"/>
<!--配置切面及配置-->
<aop:aspectorder="3"ref="sysAspect">
<!--前置通知-->
<aop:beforemethod="beforMethod"pointcut-ref="pointcut"/>
<!--后置通知-->
<aop:aftermethod="afterMethod"pointcut-ref="pointcut"/>
<!--返回通知-->
<aop:after-returningmethod="afterReturnMethod"pointcut-ref="pointcut"returning="result"/>
<!--异常通知-->
<aop:after-throwingmethod="afterThrowingMethod"pointcut-ref="pointcut"throwing="ex"/>
<aop:aroundmethod="aroundMethod"pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
定义的切面bean就是我们自定义的切面类,然后配置AOP(aop:config)。先定义切面范围pointcut。余下的就是制定aop的切面类、优先级然后再详细配置切面的通知。这样就跟注解的方式产生的效果一致了。
本文内容总结:
原文链接:https://www.cnblogs.com/qinglangyijiu/p/8425653.html