一、注解配置方式
1.添加依赖:
<dependency><groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
<!-- aop aspect注解导包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
2.在spring-mvc的配置文件中加入AOP的配置
<!-- AOP 注解方式 ;定义Aspect -->
<!-- 启动AspectJ支持 只对扫描过的bean有效-->
<context:component-scan base-package="com.yuanguo.systemManage.aop"/>
<aop:aspectj-autoproxy proxy-target-class="true" />
3.自定义LoggerAspect 类
package com.yuanguo.systemManage.aop;
import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect //该标签把LoggerAspect类声明为一个切面
@Order(1) //设置切面的优先级:如果有多个切面,可通过设置优先级控制切面的执行顺序(数值越小,优先级越高)
@Component //该标签把LoggerAspect类放到IOC容器中
public class LoggerAspect {
/**
* 定义一个方法,用于声明切入点表达式,方法中一般不需要添加其他代码
* 使用@Pointcut声明切入点表达式
* 后面的通知直接使用方法名来引用当前的切点表达式;如果是其他类使用,加上包名即可
*/
@Pointcut("execution(public * com.yuanguo.systemManage.web.*Controller.*(..))")
public void declearJoinPointExpression(){}
/**
* 前置通知
* @param joinPoint
*/
@Before("declearJoinPointExpression()") //该标签声明次方法是一个前置通知:在目标方法开始之前执行
public void beforMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("前置通知-------------开始"+methodName+" begin. param<"+ args+">");
}
/**
* 后置通知(无论方法是否发生异常都会执行,所以访问不到方法的返回值)
* @param joinPoint
*/
@After("declearJoinPointExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("后置通知-------------开始"+methodName+"------------结束.");
}
/**
* 返回通知(在方法正常结束执行的代码)
* 返回通知可以访问到方法的返回值!
* @param joinPoint
*/
@AfterReturning(value="declearJoinPointExpression()",returning="result")
public void afterReturnMethod(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("返回通知-------------开始"+methodName+" end.result<"+result+">");
}
/**
* 异常通知(方法发生异常执行的代码)
* 可以访问到异常对象;且可以指定在出现特定异常时执行的代码
* @param joinPoint
* @param ex
*/
@AfterThrowing(value="declearJoinPointExpression()",throwing="ex")
public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("异常通知-------------开始"+methodName+" end.ex message<"+ex+">");
}
/**
* 环绕通知(需要携带类型为ProceedingJoinPoint类型的参数)
* 环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin 类型的参数可以决定是否执行目标方法
* 且环绕通知必须有返回值,返回值即目标方法的返回值
* @param point
*/
@Around(value="declearJoinPointExpression()")
public Object aroundMethod(ProceedingJoinPoint point){
Object result = null;
String methodName = point.getSignature().getName();
try {
//前置通知
System.out.println("前置通知------环绕通知-------"+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">");
//执行目标方法
result = point.proceed();
//后置通知
System.out.println("后置通知------环绕通知-------"+ methodName+" end.");
} catch (Throwable e) {
//异常通知
System.out.println("异常通知------环绕通知-------"+methodName+" end.ex message<"+e+">");
throw new RuntimeException(e);
}
//返回通知
System.out.println("返回通知------环绕通知-------"+ methodName+" end. result<"+ result+">");
return result;
}
}
在类上加上注解Aspect声明这个类是一个切面,加上component注解加入IOC容器中。Order注解是优先级,如果只有一个切面类可以不用。注解pointcut是声明注解的作用范围。execution(public * com.yuanguo.systemManage.web.*Controller.*(..))我这里用的execution表达式,代表作用com.example.controller包下所有以Controller结尾类的所有Public方法。@pointcut所描述的方法里面通常不需要内容。切面通知包含:
前置通知(@Before,在执行方法之前,参数为JoinPoint)
后置通知(@After,无论方法抛不抛异常都会执行,所以获取不到方法的返回值。参数为JoinPoint)
返回通知(@AfterReturning,在方法正常结束后执行,可以获取到方法的返回值。参数为JoinPoint和result(Object))
异常通知(@AfterThrowing,在方法抛出异常时执行,可以获取到异常对象,且可以指定在出现特定异常时执行的代码,参数为JoinPoint何Exception)
环绕通知(@Around,环绕通知需要携带的类型为ProceedingJoinPoint类型的参数, 环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin 类型的参数可以决定是否执行目标方法,且环绕通知必须有返回值,返回值即目标方法的返回值)
二、注解配置方式
1.在spring-mvc的配置文件中加入AOP的配置
<!-- 配置切面的Bean --><bean id="aspectBean" class="com.yuanguo.systemManage.aop.LoggerAspect"/>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut id="pointcut" expression="execution(public * com.yuanguo.systemManage.web.*Controller.*(..))"/>
<!-- 配置切面及配置 -->
<aop:aspect id="LoggerAspect" ref="aspectBean">
<!-- 前置通知 -->
<aop:before method="beforMethod" pointcut-ref="pointcut" />
<!-- 后置通知 -->
<aop:after method="afterMethod" pointcut-ref="pointcut"/>
<!-- 返回通知 -->
<aop:after-returning method="afterReturnMethod" pointcut-ref="pointcut" returning="result"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointcut" throwing="ex"/>
<aop:around method="aroundMethod" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
<aop:aspectj-autoproxy proxy-target-class="true" />
2.自定义LoggerAspect 类
package com.yuanguo.systemManage.aop;
import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component // 该标签把LoggerAspect类放到IOC容器中
public class LoggerAspect {
/**
* 前置通知
*
* @param joinPoint
*/
public void beforMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("-----前置通知-----" + methodName + " begin. param<" + args + ">");
}
/**
* 后置通知(无论方法是否发生异常都会执行,所以访问不到方法的返回值)
*
* @param joinPoint
*/
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("----后置通知-----" + methodName + " end.");
}
/**
* 返回通知(在方法正常结束执行的代码) 返回通知可以访问到方法的返回值!
*
* @param joinPoint
*/
public void afterReturnMethod(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("---返回通知---" + methodName + " end.result<" + result + ">");
}
/**
* 异常通知(方法发生异常执行的代码) 可以访问到异常对象;且可以指定在出现特定异常时执行的代码
*
* @param joinPoint
* @param ex
*/
public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("-----异常通知----" + methodName + " end.ex message<" + ex + ">");
}
/**
* 环绕通知(需要携带类型为ProceedingJoinPoint类型的参数) 环绕通知包含前置、后置、返回、异常通知;ProceedingJoinPoin
* 类型的参数可以决定是否执行目标方法 且环绕通知必须有返回值,返回值即目标方法的返回值
*
* @param point
*/
public Object aroundMethod(ProceedingJoinPoint point) {
Object result = null;
String methodName = point.getSignature().getName();
try {
// 前置通知
System.out.println("---环绕通知-----前置通知--" + methodName + " start. param<" + Arrays.asList(point.getArgs()) + ">");
// 执行目标方法
result = point.proceed();
// 返回通知
System.out.println("---环绕通知-----返回通知---" + methodName + " end. result<" + result + ">");
} catch (Throwable e) {
// 异常通知
System.out.println("--环绕通知----异常通知----" + methodName + " end.ex message<" + e + ">");
throw new RuntimeException(e);
}
// 后置通知
System.out.println("--环绕通知----后置通知----" + methodName + " end.");
return result;
}
}