步骤
1.导入jar包:
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.2.4.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
spring-beans-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar
com.springsource.org.apache.commons.logging-1.1.1.jar
2.在配置文件中加入aop 的命名空间
xmlns:aop=“http://www.springframework.org/schema/aop”
3.基于注解的方式
a.在配置文件中加入如下配置:
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.atguigu.spring.aop.impl"></context:component-scan>
<!-- 使用AsoectJ 注解起作用:自动匹配的类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
b.把横切关注点的代码抽象到切面的类中
i.首先是需要把该类放入到IOC容器中,即加入@Component 注解
ii.切面还需要加入@Aspect 注解
@Aspect
@Component
public class LoggingAspect {
}
c.在类中声明各种通知
i.声明一个方法
ii.在方法前加入一个@Before/@After/@Around/@AfterReturning/@AfterThrowing 注解
- 前置通知@Before
@Aspect
@Component
public class LoggingAspect {
//声明该方法是一个前置通知,在目标方法之前执行
@Before("execution(* com.atguigu.spring.aop.impl.*.*(..))")
public void beforeMethod() {
System.out.println("The method begins");
}
}
d.可以在通知方法中声明一个类型为 JoinPoint 的参数,然后就能访问链接细节,入方法名称和参数值
@Aspect
@Component
public class LoggingAspect {
//声明该方法是一个前置通知,在目标方法之前执行
@Before("execution(* com.atguigu.spring.aop.impl.*.*(..))")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("The method "+ methodName +" begins with" + args);
}
}
- 后置通知@After
/**
*目标方法执行后(无论是否发生异常),执行的通知
*在后置通知中还不能访问目标方法执行的结果
*/
@After("execution(* com.atguigu.spring.aop.impl.*.*(..))")
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The method "+ methodName +" end ");
}
- 返回通知
//在方法正常结束后执行的代码,可以访问到方法的返回值
@AfterReturning(value = "execution(* com.atguigu.spring.aop.impl.*.*(..))" , returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName+ " end result:" + result);
}
- 异常通知
//在方法出现异常时会执行的代码,可以访问到异常对象,且可以指定再出现特定异常时在执行通知代码
@AfterThrowing(value = "execution(* com.atguigu.spring.aop.impl.*.*(..))",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The method " + methodName +" occurs exception:" + ex );
}
- 环绕通知
/**
* 环绕通知需要携带ProceedingJoinPoint 类型参数,
*环绕通知类似于动态代理的全过程:ProceedingJoinPoint 类型的参数可以决定是否执行目标方法
*且环绕通知必须有返回值,返回值即为目标方法的返回值
*/
@Around("execution(* com.atguigu.spring.aop.impl.*.*(..)))")
public Object aroundMethod(ProceedingJoinPoint pjd) {
Object result = null;
String methodName = pjd.getSignature().getName();
//执行方法
try {
//前置通知
System.out.println("The method " + methodName+ " begins with" + Arrays.asList(pjd.getArgs()));
result = pjd.proceed();
//返回通知
System.out.println("The method " + methodName + " end with:" + result);
} catch (Throwable e) {
System.out.println("The method " + methodName + " occurs exception:" + e);
}
System.out.println("The method " + methodName + " ends ");
return 100;
}
这里我们可以看到每次申明通知时都要写:
execution(* com.atguigu.spring.aop.impl.*.*(..))
所以我们可以把它提取出来
- 定义一个方法,用于声明切入点表达式,该方法中在不需要填入其他的代码
- 使用@Pointcut 来声明切入点表达式,后面的其他通知直接使用方法名来引用当前的切入点表达式
@Pointcut("execution(* com.atguigu.spring.aop.impl.*.*(..)))")
public void declareJoinPointExpression() {}
@Before("declareJoinPointExpression()")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("The method "+ methodName +" begins with" + args);
}
- 如果是外面的类引用该表达式则使用 类名.方法名
@Aspect
@Component
public class VlidationAspect {
@Before("LoggingAspect.declareJoinPointExpression()")
public void validataArgs(JoinPoint joinPoint) {
System.out.println("--->validate:" +Arrays.asList(joinPoint.getArgs()));
}
}
另外:如果有多个切面,我们可以使用@Order 指明切面的优先级
@Order(1)
@Aspect
@Component
public class VlidationAspect {
}
@Order(2)
@Aspect
@Component
public class LoggingAspect {
}