一、声明一个切面类
1、首先要将这个类放入容器中,基于注解,在类头信息加入@Component
2、将这个类声明成切面类,在头信息加入@Aspect注解
3、可以基于切面中的方法,比如前置通知,后置通知,返回通知,异常通知,以及环绕通知写自己的业务逻辑,定义切点"execution(* com.liyi.service.*.*(..))",即那些方法需要执行这些方法。如果想获取到方法的名字和参数,可以在方法中加入JoinPoint参数,可以获取到进入切面的方法细节。
3.1 前置通知:执行目标方法前拦截到的方法。没有特殊注意的地方,只需要一个连接点,JoinPoint,即可获取拦截目标方 法以及请求参数。
3.2 后置通知: 切面的后置通知,不管方法是否抛出异常,都会走这个方法。只需要一个连接点,JoinPoint,即可获取当 前结束的方法名称。
3.3 返回通知: 在方法正常执行通过之后执行的通知叫做返回通知。此时注意,不仅仅使用JoinPoint获取连接 点信息,同时要在返回通知注解里写入,resut="result"。在切面方法参数中加入Object result,用于接受返回通知 的返回结果。如果目标方法方法是void返回类型则返回NULL
3.4 异常通知: 在执行目标方法过程中,如果方法抛出异常则会走此方法。和返回通知很相似,在注解中 加入,throwing="ex",在切面方法中加入Exection ex用于接受异常信息
3.5 环绕通知:环绕通知需要携带ProceedingJoinPoint 这个类型的参数,环绕通知类似于动态代理的全过程 ProceedingJoinPoint类型的参数可以决定是否执行目标函数环绕通知必须有返回值。其实就是包含了所有通知的全 过程
四、最后别忘了在applicationContent.xml中声明aspect的代理对象,即初始化spring 容器的时候,spring自动对切点生成代理对象
<!-- 配置aspect 自动为匹配的类 产生代理对象 -->
<aop:aspectj-autoproxy>
Ⅱ 接下来 直接粘贴代码,很直观。
@Component @Aspect public class LoggingAspect { /** * 切面的前置方法 即方法执行前拦截到的方法 记录并输出 * 在目标方法执行之前的通知 * @param joinPoint */ @Before("execution(* com.liyi.service.*.*(..))")//第一个星号是否方法的返回值 第二个星是只service的所有子包 另一个是任意方法 public void beforeMethod(JoinPoint joinPoint){ System.out.println("======================方法开始======================"); Object object = joinPoint.getSignature(); String methodName = joinPoint.getSignature().getName(); List<Object> list = Arrays.asList(joinPoint.getArgs()); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String rightnow=sdf.format(date); System.out.println(rightnow+"执行了【"+object+"方法开始执行......】"); System.out.println("******参数"+list+"******"); } /** * 切面的后置方法,不管抛不抛异常都会走此方法 * 在目标方法执行之后的通知 * @param joinPoint */ @After("execution(* com.liyi.service.*.*(..))") public void afterMethod(JoinPoint joinPoint){ Object object = joinPoint.getSignature(); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String rightnow=sdf.format(date); System.out.println(rightnow+"执行了【"+object+"方法结束......】"); } /** * 在方法正常执行通过之后执行的通知叫做返回通知 * 可以返回到方法的返回值 在注解后加入returning * @param joinPoint */ @AfterReturning(value="execution(* com.liyi.service.*.*(..))",returning="result") public void afterReturn(JoinPoint joinPoint,Object result ){ Object object = joinPoint.getSignature(); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String rightnow=sdf.format(date); System.out.println(rightnow+"执行了【"+object+"方法正常执行结束......】"+"【返回结果:"+result+"】"); System.out.println("√√√√√√√√√√√√√√√√√√√√√√方法结束√√√√√√√√√√√√√√√√√√√√√√"); } /** * 在目标方法非正常执行完成 发生异常 抛出异常的时候会走此方法 * 获得异常可以用throwing * @param joinPoint * @param ex */ @AfterThrowing(value="execution(* com.liyi.service.*.*(..))",throwing="ex") public void afterThrowing(JoinPoint joinPoint,Exception ex ){ Object object = joinPoint.getSignature(); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String rightnow=sdf.format(date); System.out.println(rightnow+"执行了【"+object+"方法发生异常......】"+"【异常报告:"+ex+"】"); System.out.println("xxxxxxxxxxxxxxxxxx方法发生异常结束xxxxxxxxxxxxxxxxxx"); } /** * 环绕通知需要携带ProceedingJoinPoint 这个类型的参数 * 环绕通知类似于动态代理的全过程 ProceedingJoinPoint类型的参数可以决定是否执行目标函数 * 环绕通知必须有返回值 * @param proceedingJoinPoint * @return */ // @Around(value="execution(* com.liyi.service.*.*(..))") // public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){ // Object result=null; // Object classMethod=proceedingJoinPoint.getSignature(); // Date date = new Date(); // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // String rightnow=sdf.format(date); // try { // //前置通知 // System.out.println(rightnow+"环绕通知执行了【"+classMethod+"方法开始执行......】"); // //执行目标方法 // result = proceedingJoinPoint.proceed(); // //返回通知 // System.out.println(rightnow+"环绕通知正常执行【"+classMethod+"方法完毕......】"+"【返回结果:】"+result); // } catch (Throwable e) { // // TODO Auto-generated catch block // e.printStackTrace(); // //异常通知 // System.out.println(rightnow+"环绕通知非正常执行【"+classMethod+"方法完毕,抛出异常......】"+"【返回异常:】"+e); // } // //后置通知 // System.out.println(rightnow+"环绕通知执行【"+classMethod+"方法完毕】"); // return result; // } }
最后说明一点:所有通知类型都能获取到方法的相关参数,只有返回通知和环绕通能得到切面方法的返回值