AOP面向切面编程
1).引入jar包
2).在配置文件中加入aop的命名空间
①.在配置文件中加入如下配置:
>切面首先是一个IOC中的bean,即@Component注解
>切面还需要加入@Aspect注解
③.再类中声明各种通知:
>声明一个方法
>在方法前加入@Before、@After、@AfterRunning、@AfterThrowing、@Around等注解
@Before:前置通知,在方法执行之前执行
@After:后置通知,在方法执行之后执行(1.无论是否发生异常。2.在后置通知中还不能访问目标方法的执行结果)。
@AfterReturning:返回通知,在方法返回结果之后执行(返回通知可以访问到方法的返回值)。
@AfterThrowing:异常通知,在方法抛出异常之后
@Around:环绕通知,围绕着方法执行。
④.可以在通知方法中声明一个类型为JoinPoint的参数。然后就能访问链接细节。如方法名称和参数值等
整体切面类代码:
1).引入jar包
2).在配置文件中加入aop的命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
3).基于注解的方式
①.在配置文件中加入如下配置:
<!-- 使AspectJ注解起作用:为自动匹配的类生成代理对象 -->
<aop:aspectj-autoproxy />
②.把横切关注点的代码抽象到切面的类中。
>切面首先是一个IOC中的bean,即@Component注解
>切面还需要加入@Aspect注解
③.再类中声明各种通知:
>声明一个方法
>在方法前加入@Before、@After、@AfterRunning、@AfterThrowing、@Around等注解
@Before:前置通知,在方法执行之前执行
@After:后置通知,在方法执行之后执行(1.无论是否发生异常。2.在后置通知中还不能访问目标方法的执行结果)。
@AfterReturning:返回通知,在方法返回结果之后执行(返回通知可以访问到方法的返回值)。
@AfterThrowing:异常通知,在方法抛出异常之后
@Around:环绕通知,围绕着方法执行。
④.可以在通知方法中声明一个类型为JoinPoint的参数。然后就能访问链接细节。如方法名称和参数值等
@Aspect
@Component
public class ServiceRuntimeAdvice {
@Around("execution(* com.city.office.service.impl.*.*(..))")
public Object methodRuntime(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前");
Object retVal = pjp.proceed();
System.out.println("环绕后");
return retVal;
}
}
以上 * 占位符 分别代表:任意返回类型、包中的所有类,类中的所有方法。(..)代表任意参数
整体切面类代码:
package com.city.office.advice;
import java.util.Arrays;
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;
@Order(1)//指定优先级大小,值越小优先级越高。
@Aspect
@Component
public class ServiceRuntimeAdvice {
/*
* 定义一个方法,用于声明切入点表达式。一般地,该方法中再不需要填入其他的代码。
* 后面引入切入点时,引用该方法即可
* */
@Pointcut("execution(* com.city.office.service.impl.*.*(..))")
public void declareJoinPointExpression(){}
/*
* 环绕通知需要携带ProceedingJoinPoint类型的参数。
* 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
* 且环绕通知必须有返回值,返回值即为目标方法的返回值。
* */
@Around("declareJoinPointExpression()")
public Object methodRuntime(ProceedingJoinPoint pjp){
Object result=null;
String methodName=pjp.getSignature().getName();
//执行目标方法
try {
//前置通知
System.out.println("The method: "+methodName+" begin with "+Arrays.asList(pjp.getArgs()));
result= pjp.proceed();
//返回通知
System.out.println("The method "+methodName+" ends with "+result);
} catch (Throwable e) {
//异常通知
System.out.println("The method "+methodName+" occurs exception: "+e);
throw new RuntimeException(e);
}
//后置通知
System.out.println("The method "+methodName+" ends");
return result;
}
@Before("declareJoinPointExpression()")
public void methodBefore(JoinPoint jp){
String methodName=jp.getSignature().getName();
System.out.println("The method: "+methodName+" before");
}
@After("declareJoinPointExpression()")
public void methodAfter(JoinPoint jp){
String methodName=jp.getSignature().getName();
System.out.println("The method: "+methodName+" after ");
}
@AfterReturning(value="declareJoinPointExpression()",
returning="result")
public void methodAfterReturning(JoinPoint jp,Object result){
String methodName=jp.getSignature().getName();
System.out.println("The method: "+methodName+" ends with "+result);
}
/**
* 参数Exception ex:可以访问到异常对象,且可以指定在出现特定异常时执行通知代码
*
* */
@AfterThrowing(value="declareJoinPointExpression()",
throwing="ex")
public void methodAfterThrowing(JoinPoint jp,Exception ex){
String methodName=jp.getSignature().getName();
System.out.println("The method: "+methodName+" occurs excetion: "+ex);
}
}
4).基于xml文件的配置