zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    September 17th 2016 Week 38th Saturday
    【2016-09-16】UbuntuServer14.04或更高版本安装问题记录
    September 16th 2016 Week 38th Friday
    September 11th 2016 Week 38th Sunday
    September 12th 2016 Week 38th Monday
    September 10th 2016 Week 37th Saturday
    September 9th 2016 Week 37th Friday
    c++暂停
    八皇后问题
    ( 转转)Android初级开发第九讲--Intent最全用法(打开文件跳转页面等)
  • 原文地址:https://www.cnblogs.com/linhongwenBlog/p/11892160.html
Copyright © 2011-2022 走看看