spring AOP-切面编程

首先学习aop切面的顺序:

 

  • 前置通知:(Before advice)表明在连接点执行之前执行的动作。

  @Before("controllerLog()")

  • 环绕通知:(Around Advice) 环绕可以看作是包含前置通知和后置通知的一个通知,先了解,后面具体理解。

  @Around("controllerLog()")

  • 后置通知:(After returning advice)在某个连接点完成后通知,比如一个方法没有抛出任何异常,正常返回【第一个参数还是指定切点,第二个参数指定的是返回值】
  @AfterReturning(value = "controllerLog()",returning = "obj")
  • 异常通知:(After throwing advice) 在方法异常推出时候执行的通知。【这里和上面的后置通知差不多,不过第二个参数是一个异常类型对象】
  @AfterThrowing(value = "controllerLog()", throwing = "ex")
  • 最终通知:(After advice) 在连接点退出时候执行的通知。不论是正常退出还是异常退出。

   @After("controllerLog()")

 

正常返回:

 

 

异常返回:

 

 

 

 

 

 

 

学习切面编程的时候学到两种方式。下面阐述一下

公共部分

引入aop包

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

1.直接配置类路径进行切面编程

package com.whalecloud.uip.client.loggeraspect;

import com.alibaba.fastjson.JSONObject;
import com.whalecloud.common.cfg.Constants;
import com.whalecloud.common.component.ExteParamObtain;
import com.whalecloud.common.domain.CfgReqInfo;
import com.whalecloud.common.domain.ReqServiceBean;
import com.whalecloud.common.result.IomResult;
import com.whalecloud.common.util.BeetlTemplateUtil;
import com.whalecloud.common.util.MapToXmlUtils;
import com.whalecloud.uip.client.feign.DataSourceFeignClient;
import org.apache.commons.collections.MapUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


@Aspect
@Component
public class WebLogAspect {

    private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);


    /**
     * Service层切点
     */
    @Pointcut("execution(* com.whalecloud.uip.client.service.ToRestService.invokeRestReq(com.whalecloud.common.domain.ReqServiceBean)) || execution(* com.whalecloud.uip.client.service.ToWebserviceService.invokeWebServiceReq(com.whalecloud.common.domain.ReqServiceBean))")
    public void controllerAspect() {
    }

    /**
     * 配置Service环绕通知,使用在方法aspect()上注册的切入点
     *
     * @param point 切点
     * @return
     * @throws Throwable
     */
    @Around("controllerAspect()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {/*获取方法的参数值*/
        Map<String, Object> paramMap = getParam(point);
        ReqServiceBean reqServiceBean = (ReqServiceBean) MapUtils.getObject(paramMap, "reqServiceBean");
      /*获取结果*/
result = (IomResult)point.proceed();return result; } /** * 获取参数的列表 * * @param joinPoint * @return */ private Map<String, Object> getParam(ProceedingJoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); String[] parameterNames = pnd.getParameterNames(method); Map<String, Object> paramMap = new HashMap<>(); assert parameterNames != null; for (int i = 0; i < parameterNames.length; i++) { paramMap.put(parameterNames[i], args[i]); } return paramMap; } }

 

proceedingJoinPoint  可以拿到入参值和返回值。进行切面操作。

 

2.根据注解进行切面编程

1.先写个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLog {
    String type();
}

 

 

2.AOP配置

@Aspect
@Component
public class AOPConfig {
 
    @Around(value = "@annotation(OperationLog)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("方法环绕begin...参数:"+Arrays.toString(proceedingJoinPoint.getArgs()));
        try {
            Object ret= proceedingJoinPoint.proceed();
            System.out.println("方法环绕end...结果:"+ret);
            return ret;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }
 
    @Before(value = "@annotation(OperationLog)")
    public void doBefore(JoinPoint joinPoint){
        ServletRequestAttributes requestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest req= requestAttributes.getRequest();
        System.out.println("uri:"+req.getRequestURI());
        System.out.println("执行方法前 : " + Arrays.toString(joinPoint.getArgs()));
    }
 
    @After(value = "@annotation(OperationLog)")
    public void after(JoinPoint joinPoint){
        System.out.println("执行方法后:"+ Arrays.toString(joinPoint.getArgs()));
    }
 
    @AfterReturning(pointcut = "@annotation(OperationLog)",returning = "ret")
    public void doAfterReturning(Object ret){
        System.out.println("方法的返回值 : " + ret);
    }
 
    @AfterThrowing(pointcut = "@annotation(OperationLog)",throwing = "ex")
    public void AfterThrowing(JoinPoint joinPoint,Throwable ex){
        System.out.println("方法执行异常 : " + ex);
    }
}

 

 

3.服务类

@RequestMapping("/aop")
@RestController
public class AOPCtrl {
 
    @Autowired
    private MessageService messageService;
 
    @RequestMapping(value = "/test",method = RequestMethod.GET)
    public String test(){
        return messageService.sendMessage("xiaoming",29);
    }
}
 
@Service
public class MessageService {
 
    @OperationLog(type = "sendMessage")
    public String sendMessage(String name,int age){
        return "this person: "+name+" age: "+age;
    }
}

 

 

4.返回结果

运行结果:
方法环绕begin...参数:[xiaoming, 29]
uri:/aop/test
执行方法前 : [xiaoming, 29]
方法环绕end...结果:this person: xiaoming age: 29
执行方法后:[xiaoming, 29]
方法的返回值 : this person: xiaoming age: 29

 

posted @ 2019-11-19 20:29  林被熊烟岛  阅读(168)  评论(0编辑  收藏  举报