SpringBoot+SpringAop通知使用实例

package com.zdj.springboot_aop;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps; // guava   24.1-jar
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

//import com.google.common.collect.Maps;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2018/3/28.
 */

/**
 * 1.先创建一个Aspect切面类
 */
@Component
@Aspect
public class WebControllerAop {

    /**
     * 2. 指定切点
     * 匹配com.zdj.springboot_aop.Controller包及其子包下面的所有类的所有方法
     */
    @Pointcut("execution(* com.zdj.springboot_aop.Controller..*.*(..))")
    public  void executeService(){

    }

    /**
     *  01 . 前置通知:方法调用前被调用
     */
    @Before("executeService()")
    public void doBeforeAdvice(JoinPoint joinPoint){//  通过JoinPoint 获取通知的签名信息,如目标方法名,目标方法参数信息等
        System.out.println("我是前置通知");
        Object[] obj=joinPoint.getArgs();//获取目标方法的参数信息
        joinPoint.getThis(); // AOP代理类信息
        joinPoint.getTarget(); // 代理的目标对象
        Signature signature=joinPoint.getSignature(); //  用的最多,通知的签名
        System.out.println("代理的方法是 : "+signature.getName()); //  打印 代理的是哪一个方法
        // AOP 代理的名字
        System.out.println("AOP 代理的名字 : "+signature.getDeclaringTypeName());
        signature.getDeclaringType();//  AOP代理类的类(class)信息

        /*
          通过RequestContextHolder获取请求信息,如session 信息 ;
         */
        //  获取RequestAttributes
        RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
        //  从requestAttributes中获取HttpServletRequest信息
        HttpServletRequest request=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        //  获取session信息
        HttpSession session=(HttpSession)requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);

        System.out.println("请求 : "+request+" ,  HttpSession : "+session);
        Enumeration<String> enumerations=request.getParameterNames();
//        Map<String,String> parameterMaps=new HashMap<>();
        Map<String,String> parameterMaps= Maps.newHashMap();
        while(enumerations.hasMoreElements()){
            String parameter=enumerations.nextElement();
            parameterMaps.put(parameter,request.getParameter(parameter));
        }

//        String str=JSON.toJSONString(parameterMaps);
        String str= JSON.toJSONString(parameterMaps);//   alibaba.fastjson
        if(obj.length>0){
            System.out.println("请求参数信息为 : "+ str );
        }

    }

    /**
     * 02  .后置返回通知
     * 需要注意:
     *      如果第一个参数是JoinPoint,则第二个参数是返回值的信息
     *      如果参数中的第一个不是JoinPoint,则第一个参数是returning中对应的参数,
     *    returning 限定了只有目标方法返回值与通知方法相应参数类型时才能
     * 执行后置返回通知,否则不执行;
     * 对于returning对应的通知方法参数为Object类型将匹配任何目标返回值
     * @param joinPoint
     * @param keys
     */
    @AfterReturning(value="execution(* com.zdj.springboot_aop.Controller..*.*(..))",returning = "keys")
    public void doAfterReturningAdvice1(JoinPoint joinPoint,Object keys){
        System.out.println("后置通知执行了!!");
        System.out.println("第一个后置返回通知的返回值是 :"+keys);
    }

    @AfterReturning(value="execution(* com.zdj.springboot_aop.Controller..*.*(..))",returning = "keys",argNames="keys")
    public void doAfterReturningAdvice2(String keys){ // 通知方法形影参数的类型是String
        System.out.println("第二个后置返回通知的返回值是 :"+keys);
    }

    /**
     *  03 . 后置异常通知
     *       定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
     *  throwing 限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,
     *      对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
     */
    @AfterThrowing(value="executeService()",throwing = "exception")
    public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){
        // 目标方法名
        System.out.println(joinPoint.getSignature().getName());
        if(exception instanceof NullPointerException){
            System.out.println("发生了空指针异常");
        }
    }


    /**
     * 04 . 后置最终通知(目标方法只要执行完了就会执行后置通知方法)
     */

    @After("executeService()")
    public void doAfterService(JoinPoint joinPoint){
        System.out.println("后置最终通知执行了!");
    }

    /**
     * 环绕通知:
     *   环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
     *   环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
     */
    @Around("execution(* com.zdj.springboot_aop.Controller..*.testAround*(..))")
    public Object doAroundService(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("环绕通知的目标方法名为 : "+proceedingJoinPoint.getSignature().getName());
        try {
            Object object=proceedingJoinPoint.proceed();
            return object;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return  null;
    }
}
 

  

 
package com.zdj.springboot_aop.Controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 创建AOP测试Controller.Created by Administrator on 2018/3/28.
 */

@RestController
@RequestMapping("/aop")
public class AopTestController {

    @RequestMapping("/testBeforeService.do")
    public String testBeforeService(String key ,String value){
        return "key : "+key+ ", value : "+value;
        /*
        url:  http://localhost:8080/aop/testBeforeService.do?key=zdj&value=123
        我是前置通知
        代理的方法是 : testBeforeService
        AOP 代理的名字 : com.zdj.springboot_aop.Controller.AopTestController
        请求 : org.apache.catalina.connector.RequestFacade@4f8cf74e ,  HttpSession : org.apache.catalina.session.StandardSessionFacade@7b37a638
        请求参数信息为 : {"value":"123","key":"zdj"}
         */
    }

    @RequestMapping("/testAfterReturning1.do")
    public String testAfterReturning1(String key){
        return "key = "+key;
        /*
            url :  http://localhost:8080/aop/testAfterReturning1.do?key=zdj&value=123
            后置通知执行了!!
            第一个后置返回通知的返回值是 :key = zdj
            第二个后置返回通知的返回值是 :key = zdj
         */
    }

    @RequestMapping("/testAfterReturning2.do")
    public Integer testAfterReturning2(Integer key){
        return key;
        /*
            url :  http://localhost:8080/aop/testAfterReturning2.do?key=111222&value=123

            后置通知执行了!!
            第一个后置返回通知的返回值是 :111222

            注 : 因第二个后置通知首参不是JoinPoint,并且相应参数类型是String,而该目标方法的返回值类型是Integer,所以第二个后置通知方法不执行
         */
    }

    @RequestMapping("/testAfterThrowing.do")
    public  String testAfterThrowing(String key){
        throw new NullPointerException();
        /*
        url : http://localhost:8080/aop/testAfterThrowing.do?key=zdk&value=123
        我是前置通知
        代理的方法是 : testAfterThrowing
        AOP 代理的名字 : com.zdj.springboot_aop.Controller.AopTestController
        请求 : org.apache.catalina.connector.RequestFacade@41b8dcce ,  HttpSession : org.apache.catalina.session.StandardSessionFacade@33c33c37
        请求参数信息为 : {"value":"123","key":"zdk"}
        testAfterThrowing
        发生了空指针异常
        */
    }

    @RequestMapping("/testAfter1.do")
    public String testAfter1(String key){
        throw new NullPointerException();
        /*
        url: http://localhost:8080/aop/testAfter1.do?key=zdj&value=123
        后置最终通知执行了!
         */
    }

    @RequestMapping("/testAfter2.do")
    public String testAfter2(String key){
        return key;
        /*
        url: http://localhost:8080/aop/testAfter2.do?key=zdj&value=123
        后置最终通知执行了!
         */
    }

    @RequestMapping("/testAroundService.do")
    public String testAroundService(String key){
        return "环绕通知 : " + key;
        /*
        url : http://localhost:8080/aop/testAroundService.do?key=1122
        环绕通知的目标方法名为 : testAroundService

        当访问 http://localhost:8080/aop/testAfter2.do?key=1122&value=sjshhjdh,不符合环绕通知的切入规则,所以环绕通知不会执行;
         */
    }

}
 
package com.zdj.springboot_aop;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Created by Dylan on 2018/6/22.
 */
@SpringBootApplication
public class StartApplication {

    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }


}

 


  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值